Attempt new blackhole explosion algos, but nothing works
This commit is contained in:
parent
1fae349547
commit
c28ff851c9
@ -20,7 +20,7 @@ import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleExplosionQueue;
|
||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.ExplosionQueue;
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryCapability;
|
||||
import ru.dbotthepony.mc.otm.capability.android.AndroidCapability;
|
||||
import ru.dbotthepony.mc.otm.capability.android.AndroidCapabilityPlayer;
|
||||
@ -131,7 +131,7 @@ public class OverdriveThatMatters {
|
||||
MinecraftForge.EVENT_BUS.register(AndroidCapabilityPlayer.Companion);
|
||||
MinecraftForge.EVENT_BUS.register(AndroidCapability.Companion);
|
||||
MinecraftForge.EVENT_BUS.register(MatterRegistry.class);
|
||||
MinecraftForge.EVENT_BUS.register(BlackHoleExplosionQueue.Companion);
|
||||
MinecraftForge.EVENT_BUS.register(ExplosionQueue.Companion);
|
||||
|
||||
FMLJavaModLoadingContext.get().getModEventBus().register(MatteryCapability.class);
|
||||
|
||||
|
@ -36,6 +36,8 @@ import ru.dbotthepony.mc.otm.block.*;
|
||||
import ru.dbotthepony.mc.otm.block.entity.*;
|
||||
import ru.dbotthepony.mc.otm.android.AndroidFeatureType;
|
||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlockEntityBlackHole;
|
||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlockEntityExplosionDebugger;
|
||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlockEntitySphereDebugger;
|
||||
import ru.dbotthepony.mc.otm.client.render.BlackHoleRenderer;
|
||||
import ru.dbotthepony.mc.otm.client.render.SkinElement;
|
||||
import ru.dbotthepony.mc.otm.core.Fraction;
|
||||
@ -114,6 +116,10 @@ public class Registry {
|
||||
public static final ResourceLocation ENERGY_COUNTER = new ResourceLocation(OverdriveThatMatters.MOD_ID, "energy_counter"); // нужен рецепт
|
||||
public static final ResourceLocation CHEMICAL_GENERATOR = new ResourceLocation(OverdriveThatMatters.MOD_ID, "chemical_generator"); // нужен рецепт
|
||||
|
||||
|
||||
public static final ResourceLocation DEBUG_EXPLOSION_SMALL = new ResourceLocation(OverdriveThatMatters.MOD_ID, "debug_explosion_small");
|
||||
public static final ResourceLocation DEBUG_SPHERE_POINTS = new ResourceLocation(OverdriveThatMatters.MOD_ID, "debug_sphere_points");
|
||||
|
||||
public static final ResourceLocation BLACK_HOLE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "black_hole");
|
||||
public static final ResourceLocation CARGO_CRATE = new ResourceLocation(OverdriveThatMatters.MOD_ID, "cargo_crate");
|
||||
|
||||
@ -251,6 +257,9 @@ public class Registry {
|
||||
public static final BlockEnergyCounter ENERGY_COUNTER = new BlockEnergyCounter();
|
||||
public static final BlockChemicalGenerator CHEMICAL_GENERATOR = new BlockChemicalGenerator();
|
||||
|
||||
public static final BlockExplosionDebugger DEBUG_EXPLOSION_SMALL = new BlockExplosionDebugger();
|
||||
public static final BlockSphereDebugger DEBUG_SPHERE_POINTS = new BlockSphereDebugger();
|
||||
|
||||
public static final BlockBlackHole BLACK_HOLE = new BlockBlackHole();
|
||||
|
||||
public static final Block TRITANIUM_ORE = new OreBlock(
|
||||
@ -330,6 +339,9 @@ public class Registry {
|
||||
ENERGY_COUNTER.setRegistryName(Names.ENERGY_COUNTER);
|
||||
CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR);
|
||||
|
||||
DEBUG_EXPLOSION_SMALL.setRegistryName(Names.DEBUG_EXPLOSION_SMALL);
|
||||
DEBUG_SPHERE_POINTS.setRegistryName(Names.DEBUG_SPHERE_POINTS);
|
||||
|
||||
TRITANIUM_BLOCK.setRegistryName(Names.TRITANIUM_BLOCK);
|
||||
TRITANIUM_STRIPED_BLOCK.setRegistryName(Names.TRITANIUM_STRIPED_BLOCK);
|
||||
CARBON_FIBRE_BLOCK.setRegistryName(Names.CARBON_FIBRE_BLOCK);
|
||||
@ -362,6 +374,9 @@ public class Registry {
|
||||
event.getRegistry().register(ENERGY_COUNTER);
|
||||
event.getRegistry().register(CHEMICAL_GENERATOR);
|
||||
|
||||
event.getRegistry().register(DEBUG_EXPLOSION_SMALL);
|
||||
event.getRegistry().register(DEBUG_SPHERE_POINTS);
|
||||
|
||||
for (var crate : CRATES) {
|
||||
event.getRegistry().register(crate);
|
||||
}
|
||||
@ -391,6 +406,9 @@ public class Registry {
|
||||
public static final Item ENERGY_COUNTER = new BlockItem(Blocks.ENERGY_COUNTER, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
|
||||
public static final Item CHEMICAL_GENERATOR = new BlockItem(Blocks.CHEMICAL_GENERATOR, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
|
||||
|
||||
public static final Item DEBUG_EXPLOSION_SMALL = new BlockItem(Blocks.DEBUG_EXPLOSION_SMALL, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
|
||||
public static final Item DEBUG_SPHERE_POINTS = new BlockItem(Blocks.DEBUG_SPHERE_POINTS, new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
|
||||
|
||||
public static final Item TRITANIUM_ORE_CLUMP = new Item(new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
|
||||
public static final Item TRITANIUM_INGOT = new Item(new Item.Properties().stacksTo(64).tab(OverdriveThatMatters.CREATIVE_TAB));
|
||||
|
||||
@ -489,6 +507,9 @@ public class Registry {
|
||||
ENERGY_COUNTER.setRegistryName(Names.ENERGY_COUNTER);
|
||||
CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR);
|
||||
|
||||
DEBUG_EXPLOSION_SMALL.setRegistryName(Names.DEBUG_EXPLOSION_SMALL);
|
||||
DEBUG_SPHERE_POINTS.setRegistryName(Names.DEBUG_SPHERE_POINTS);
|
||||
|
||||
TRITANIUM_ORE.setRegistryName(Names.TRITANIUM_ORE);
|
||||
DEEPSLATE_TRITANIUM_ORE.setRegistryName(Names.DEEPSLATE_TRITANIUM_ORE);
|
||||
TRITANIUM_RAW_BLOCK.setRegistryName(Names.TRITANIUM_RAW_BLOCK);
|
||||
@ -558,6 +579,9 @@ public class Registry {
|
||||
event.getRegistry().register(ENERGY_COUNTER);
|
||||
event.getRegistry().register(CHEMICAL_GENERATOR);
|
||||
|
||||
event.getRegistry().register(DEBUG_EXPLOSION_SMALL);
|
||||
event.getRegistry().register(DEBUG_SPHERE_POINTS);
|
||||
|
||||
event.getRegistry().register(TRITANIUM_ORE);
|
||||
event.getRegistry().register(DEEPSLATE_TRITANIUM_ORE);
|
||||
event.getRegistry().register(TRITANIUM_RAW_BLOCK);
|
||||
@ -633,6 +657,9 @@ public class Registry {
|
||||
public static final BlockEntityType<BlockEntityEnergyCounter> ENERGY_COUNTER = BlockEntityType.Builder.of(BlockEntityEnergyCounter::new, Blocks.ENERGY_COUNTER).build(null);
|
||||
public static final BlockEntityType<BlockEntityChemicalGenerator> CHEMICAL_GENERATOR = BlockEntityType.Builder.of(BlockEntityChemicalGenerator::new, Blocks.CHEMICAL_GENERATOR).build(null);
|
||||
|
||||
public static final BlockEntityType<BlockEntityExplosionDebugger> DEBUG_EXPLOSION_SMALL = BlockEntityType.Builder.of(BlockEntityExplosionDebugger::new, Blocks.DEBUG_EXPLOSION_SMALL).build(null);
|
||||
public static final BlockEntityType<BlockEntitySphereDebugger> DEBUG_SPHERE_POINTS = BlockEntityType.Builder.of(BlockEntitySphereDebugger::new, Blocks.DEBUG_SPHERE_POINTS).build(null);
|
||||
|
||||
static {
|
||||
ANDROID_STATION.setRegistryName(Names.ANDROID_STATION);
|
||||
BATTERY_BANK.setRegistryName(Names.BATTERY_BANK);
|
||||
@ -651,6 +678,9 @@ public class Registry {
|
||||
ITEM_MONITOR.setRegistryName(Names.ITEM_MONITOR);
|
||||
ENERGY_COUNTER.setRegistryName(Names.ENERGY_COUNTER);
|
||||
CHEMICAL_GENERATOR.setRegistryName(Names.CHEMICAL_GENERATOR);
|
||||
|
||||
DEBUG_EXPLOSION_SMALL.setRegistryName(Names.DEBUG_EXPLOSION_SMALL);
|
||||
DEBUG_SPHERE_POINTS.setRegistryName(Names.DEBUG_SPHERE_POINTS);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
@ -673,6 +703,8 @@ public class Registry {
|
||||
event.getRegistry().register(ITEM_MONITOR);
|
||||
event.getRegistry().register(ENERGY_COUNTER);
|
||||
event.getRegistry().register(CHEMICAL_GENERATOR);
|
||||
event.getRegistry().register(DEBUG_EXPLOSION_SMALL);
|
||||
event.getRegistry().register(DEBUG_SPHERE_POINTS);
|
||||
|
||||
// OverdriveThatMatters.LOGGER.info("Registered block entities");
|
||||
}
|
||||
|
@ -6,18 +6,9 @@ import net.minecraft.core.Vec3i
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import java.util.function.Consumer
|
||||
|
||||
operator fun Vec3i.plus(direction: Vec3i): Vec3i = this.offset(direction)
|
||||
operator fun Vec3i.plus(direction: Direction): Vec3i = this.offset(direction.normal)
|
||||
operator fun Vec3i.minus(direction: Vec3i): Vec3i = this.subtract(direction)
|
||||
operator fun Vec3i.minus(direction: Direction): Vec3i = this.subtract(direction.normal)
|
||||
|
||||
operator fun BlockPos.plus(direction: Vec3i): BlockPos = this.offset(direction)
|
||||
operator fun BlockPos.plus(direction: Direction): BlockPos = this.offset(direction.normal)
|
||||
operator fun BlockPos.minus(direction: Vec3i): BlockPos = this.subtract(direction)
|
||||
operator fun BlockPos.minus(direction: Direction): BlockPos = this.subtract(direction.normal)
|
||||
|
||||
operator fun Direction.unaryMinus(): Direction = this.opposite
|
||||
operator fun Vec3i.unaryMinus(): Vec3i = Vec3i(-x, -y, -z)
|
||||
operator fun BlockPos.unaryMinus(): BlockPos = BlockPos(-x, -y, -z)
|
||||
|
@ -0,0 +1,50 @@
|
||||
package ru.dbotthepony.mc.otm.block
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.EntityBlock
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.material.Material
|
||||
import ru.dbotthepony.mc.otm.Registry
|
||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlockEntityExplosionDebugger
|
||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlockEntitySphereDebugger
|
||||
|
||||
class BlockExplosionDebugger : Block(Properties.of(Material.STONE)), EntityBlock {
|
||||
override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity {
|
||||
return BlockEntityExplosionDebugger(p_153215_, p_153216_)
|
||||
}
|
||||
|
||||
override fun <T : BlockEntity?> getTicker(
|
||||
p_153212_: Level,
|
||||
p_153213_: BlockState,
|
||||
p_153214_: BlockEntityType<T>
|
||||
): BlockEntityTicker<T>? {
|
||||
if (!p_153212_.isClientSide && p_153214_ === Registry.BlockEntities.DEBUG_EXPLOSION_SMALL) {
|
||||
return BlockEntityTicker {_, _, _, t -> if (t is BlockEntityExplosionDebugger) t.tick()}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class BlockSphereDebugger : Block(Properties.of(Material.STONE)), EntityBlock {
|
||||
override fun newBlockEntity(p_153215_: BlockPos, p_153216_: BlockState): BlockEntity {
|
||||
return BlockEntitySphereDebugger(p_153215_, p_153216_)
|
||||
}
|
||||
|
||||
override fun <T : BlockEntity?> getTicker(
|
||||
p_153212_: Level,
|
||||
p_153213_: BlockState,
|
||||
p_153214_: BlockEntityType<T>
|
||||
): BlockEntityTicker<T>? {
|
||||
if (!p_153212_.isClientSide && p_153214_ === Registry.BlockEntities.DEBUG_SPHERE_POINTS) {
|
||||
return BlockEntityTicker {_, _, _, t -> if (t is BlockEntitySphereDebugger) t.tick()}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
@ -31,6 +31,7 @@ import ru.dbotthepony.mc.otm.block.BlockMatteryRotatable
|
||||
import ru.dbotthepony.mc.otm.block.entity.worker.WorkerState
|
||||
import ru.dbotthepony.mc.otm.capability.MatteryMachineEnergyStorage
|
||||
import ru.dbotthepony.mc.otm.capability.receiveEnergy
|
||||
import ru.dbotthepony.mc.otm.core.plus
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class BlockEntityChemicalGenerator(pos: BlockPos, state: BlockState) : BlockEntityMattery(Registry.BlockEntities.CHEMICAL_GENERATOR, pos, state) {
|
||||
|
@ -3,8 +3,6 @@ package ru.dbotthepony.mc.otm.block.entity.blackhole
|
||||
import net.minecraft.client.Minecraft
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.network.Connection
|
||||
import net.minecraft.network.protocol.PacketFlow
|
||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket
|
||||
@ -13,231 +11,22 @@ import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.LivingEntity
|
||||
import net.minecraft.world.entity.item.ItemEntity
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Explosion
|
||||
import net.minecraft.world.level.ExplosionDamageCalculator
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.levelgen.structure.BoundingBox
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.saveddata.SavedData
|
||||
import net.minecraft.world.phys.AABB
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraftforge.event.TickEvent
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent
|
||||
import ru.dbotthepony.mc.otm.Registry
|
||||
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleExplosionQueue.Companion.factory
|
||||
import ru.dbotthepony.mc.otm.core.Fraction
|
||||
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 java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.sqrt
|
||||
|
||||
private object BlackHoleExplosionDamageCalculator : ExplosionDamageCalculator() {
|
||||
override fun getBlockExplosionResistance(
|
||||
explosion: Explosion,
|
||||
getter: BlockGetter,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
fstate: FluidState
|
||||
): Optional<Float> {
|
||||
return if (state.isAir && fstate.isEmpty) Optional.empty() else Optional.of(
|
||||
Math.sqrt(
|
||||
Math.max(
|
||||
0f,
|
||||
Math.max(
|
||||
state.getExplosionResistance(getter, pos, explosion),
|
||||
fstate.getExplosionResistance(getter, pos, explosion)
|
||||
)
|
||||
).toDouble()
|
||||
).toFloat()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private data class RingExplosion(val x: Double, val y: Double, val z: Double, val radius: Double, val strength: Float) {
|
||||
fun serializeNBT(): CompoundTag {
|
||||
return CompoundTag().also {
|
||||
it["x"] = x
|
||||
it["y"] = y
|
||||
it["z"] = z
|
||||
it["radius"] = radius
|
||||
it["strength"] = strength
|
||||
}
|
||||
}
|
||||
|
||||
fun explode(queue: BlackHoleExplosionQueue) {
|
||||
val fragments = radius.toInt() * 8
|
||||
val stackStep = Math.PI / fragments.toDouble()
|
||||
val sectorStep = Math.PI / fragments.toDouble() * 2
|
||||
|
||||
for (stack in 0 until fragments) {
|
||||
val stackAngle = Math.PI / 2 - stack * stackStep
|
||||
val xy = radius * 15 * cos(stackAngle)
|
||||
val z = radius * 15 * sin(stackAngle)
|
||||
|
||||
for (sector in 0 until fragments) {
|
||||
val sectorAngle = sector * sectorStep
|
||||
|
||||
queue.explode(
|
||||
this.x + xy * cos(sectorAngle),
|
||||
this.y + xy * sin(sectorAngle),
|
||||
this.z + z,
|
||||
strength
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun deserializeNBT(tag: CompoundTag): RingExplosion {
|
||||
return RingExplosion(
|
||||
tag.getDouble("x"),
|
||||
tag.getDouble("y"),
|
||||
tag.getDouble("z"),
|
||||
tag.getDouble("radius"),
|
||||
tag.getFloat("strength")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class QueuedExplosion(val x: Double, val y: Double, val z: Double, val radius: Float) {
|
||||
fun serializeNBT(): CompoundTag {
|
||||
return CompoundTag().also {
|
||||
it["x"] = x
|
||||
it["y"] = y
|
||||
it["z"] = z
|
||||
it["radius"] = radius
|
||||
}
|
||||
}
|
||||
|
||||
fun explode(level: Level) {
|
||||
level.explode(
|
||||
null,
|
||||
Registry.DAMAGE_HAWKING_RADIATION,
|
||||
BlackHoleExplosionDamageCalculator,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
radius,
|
||||
false,
|
||||
Explosion.BlockInteraction.DESTROY
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun deserializeNBT(tag: CompoundTag): QueuedExplosion {
|
||||
return QueuedExplosion(tag.getDouble("x"), tag.getDouble("y"), tag.getDouble("z"), tag.getFloat("radius"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BlackHoleExplosionQueue(private val level: ServerLevel) : SavedData() {
|
||||
private var indexExplosion = 0
|
||||
private var indexRing = 0
|
||||
private val explosions = ArrayList<QueuedExplosion>()
|
||||
private val rings = ArrayList<RingExplosion>()
|
||||
|
||||
override fun save(tag: CompoundTag): CompoundTag {
|
||||
val listExplosions = ListTag()
|
||||
val listRings = ListTag()
|
||||
|
||||
for (i in indexExplosion until explosions.size)
|
||||
listExplosions.add(explosions[i].serializeNBT())
|
||||
|
||||
for (i in indexRing until rings.size)
|
||||
listRings.add(rings[i].serializeNBT())
|
||||
|
||||
tag["explosions"] = listExplosions
|
||||
tag["rings"] = listRings
|
||||
|
||||
return tag
|
||||
}
|
||||
|
||||
fun load(tag: CompoundTag) {
|
||||
explosions.clear()
|
||||
rings.clear()
|
||||
|
||||
indexExplosion = 0
|
||||
indexRing = 0
|
||||
|
||||
for (explosion in tag.getList("explosions", Tag.TAG_COMPOUND.toInt()))
|
||||
explosions.add(QueuedExplosion.deserializeNBT(explosion as CompoundTag))
|
||||
|
||||
for (ring in tag.getList("rings", Tag.TAG_COMPOUND.toInt()))
|
||||
rings.add(RingExplosion.deserializeNBT(ring as CompoundTag))
|
||||
}
|
||||
|
||||
fun explode(x: Double, y: Double, z: Double, radius: Float) {
|
||||
explosions.add(QueuedExplosion(x, y, z, radius))
|
||||
isDirty = true
|
||||
}
|
||||
|
||||
fun explodeRing(x: Double, y: Double, z: Double, radius: Double, strength: Float) {
|
||||
rings.add(RingExplosion(x, y, z, radius, strength))
|
||||
isDirty = true
|
||||
}
|
||||
|
||||
fun tick() {
|
||||
if (explosions.size != 0) {
|
||||
setDirty()
|
||||
var iterations = 0
|
||||
|
||||
for (i in indexExplosion until explosions.size) {
|
||||
explosions[i].explode(level)
|
||||
indexExplosion++
|
||||
|
||||
if (iterations++ == 4) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (indexExplosion >= explosions.size) {
|
||||
indexExplosion = 0
|
||||
explosions.clear()
|
||||
}
|
||||
} else if (rings.size != 0) {
|
||||
if (indexRing >= rings.size) {
|
||||
indexRing = 0
|
||||
rings.clear()
|
||||
} else {
|
||||
rings[indexRing++].explode(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun factory(level: ServerLevel): BlackHoleExplosionQueue {
|
||||
return level.dataStorage.computeIfAbsent(
|
||||
{
|
||||
val factory = BlackHoleExplosionQueue(level)
|
||||
factory.load(it)
|
||||
factory
|
||||
},
|
||||
{ BlackHoleExplosionQueue(level) },
|
||||
"otm_blackhole_explosion_queue"
|
||||
)
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
fun onWorldTick(event: TickEvent.WorldTickEvent) {
|
||||
if (event.phase == TickEvent.Phase.START && event.world is ServerLevel) {
|
||||
factory(event.world as ServerLevel).tick()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BlockEntityBlackHole(p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(Registry.BlockEntities.BLACK_HOLE, p_155229_, p_155230_) {
|
||||
var mass = BASELINE_MASS
|
||||
set(mass) {
|
||||
@ -291,7 +80,7 @@ class BlockEntityBlackHole(p_155229_: BlockPos, p_155230_: BlockState) : BlockEn
|
||||
val x0 = blockPos.x + 0.5
|
||||
val y0 = blockPos.y + 0.5
|
||||
val z0 = blockPos.z + 0.5
|
||||
val queue = factory(level)
|
||||
val queue = queueForLevel(level)
|
||||
var radius = 0
|
||||
|
||||
while (radius < Math.ceil(gravitationStrength * 4)) {
|
||||
|
@ -0,0 +1,49 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.blackhole
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import ru.dbotthepony.mc.otm.Registry
|
||||
import ru.dbotthepony.mc.otm.core.plus
|
||||
import ru.dbotthepony.mc.otm.core.times
|
||||
|
||||
class BlockEntityExplosionDebugger(p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(Registry.BlockEntities.DEBUG_EXPLOSION_SMALL, p_155229_, p_155230_) {
|
||||
private var hive: ExplosionRayHive? = null
|
||||
|
||||
fun tick() {
|
||||
if (hive == null) {
|
||||
val hive = ExplosionRayHive(level as ServerLevel)
|
||||
this.hive = hive
|
||||
|
||||
val tx = blockPos.x.toDouble() + 0.5
|
||||
val ty = blockPos.y.toDouble() + 0.5
|
||||
val tz = blockPos.z.toDouble() + 0.5
|
||||
val tpos = Vec3(tx, ty, tz)
|
||||
|
||||
for (normal in ExplosionRayHive.evenlyDistributedPoints(1000)) {
|
||||
hive.addRay(normal + tpos, normal, 200.0)
|
||||
}
|
||||
}
|
||||
|
||||
hive!!.step()
|
||||
}
|
||||
}
|
||||
|
||||
class BlockEntitySphereDebugger(p_155229_: BlockPos, p_155230_: BlockState) : BlockEntity(Registry.BlockEntities.DEBUG_SPHERE_POINTS, p_155229_, p_155230_) {
|
||||
private var placed = false
|
||||
|
||||
fun tick() {
|
||||
if (!placed) {
|
||||
placed = true
|
||||
|
||||
for (normal in ExplosionRayHive.evenlyDistributedPoints(400)) {
|
||||
val multiplied = normal * 20.0
|
||||
level!!.setBlock(blockPos + BlockPos(multiplied.x, multiplied.y, multiplied.z), Blocks.COAL_BLOCK.defaultBlockState(), Block.UPDATE_ALL)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,678 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.blackhole
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.DoubleTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
import net.minecraft.nbt.Tag
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.level.BlockGetter
|
||||
import net.minecraft.world.level.Explosion
|
||||
import net.minecraft.world.level.ExplosionDamageCalculator
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.Block
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.material.FluidState
|
||||
import net.minecraft.world.level.saveddata.SavedData
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import net.minecraftforge.event.TickEvent
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent
|
||||
import org.apache.logging.log4j.LogManager
|
||||
import ru.dbotthepony.mc.otm.Registry
|
||||
import ru.dbotthepony.mc.otm.block.BlockExplosionDebugger
|
||||
import ru.dbotthepony.mc.otm.core.*
|
||||
import ru.dbotthepony.mc.otm.core.Vector
|
||||
import ru.dbotthepony.mc.otm.set
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.math.acos
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.sqrt
|
||||
|
||||
private fun round(v: Double): Int {
|
||||
return (v + 0.5).toInt()
|
||||
}
|
||||
|
||||
private val sphere = arrayOf(
|
||||
// ядро
|
||||
BlockPos(-1, -1, -1),
|
||||
BlockPos(-1, -1, 0),
|
||||
BlockPos(-1, -1, 1),
|
||||
BlockPos(-1, 0, -1),
|
||||
BlockPos(-1, 0, 0),
|
||||
BlockPos(-1, 0, 1),
|
||||
BlockPos(-1, 1, -1),
|
||||
BlockPos(-1, 1, 0),
|
||||
BlockPos(-1, 1, 1),
|
||||
BlockPos(0, -1, -1),
|
||||
BlockPos(0, -1, 0),
|
||||
BlockPos(0, -1, 1),
|
||||
BlockPos(0, 0, -1),
|
||||
BlockPos(0, 0, 0),
|
||||
BlockPos(0, 0, 1),
|
||||
BlockPos(0, 1, -1),
|
||||
BlockPos(0, 1, 0),
|
||||
BlockPos(0, 1, 1),
|
||||
BlockPos(1, -1, -1),
|
||||
BlockPos(1, -1, 0),
|
||||
BlockPos(1, -1, 1),
|
||||
BlockPos(1, 0, -1),
|
||||
BlockPos(1, 0, 0),
|
||||
BlockPos(1, 0, 1),
|
||||
BlockPos(1, 1, -1),
|
||||
BlockPos(1, 1, 0),
|
||||
BlockPos(1, 1, 1),
|
||||
|
||||
// столбы
|
||||
BlockPos(-2, 0, 0),
|
||||
BlockPos(2, 0, 0),
|
||||
BlockPos(0, 2, 0),
|
||||
BlockPos(0, -2, 0),
|
||||
BlockPos(0, 0, 2),
|
||||
BlockPos(0, 0, -2),
|
||||
)
|
||||
|
||||
private val initialDirections = arrayOf(
|
||||
Vector(1.0, 0.0, 0.0),
|
||||
Vector(-1.0, 0.0, 0.0),
|
||||
Vector(0.0, 1.0, 0.0),
|
||||
Vector(0.0, -1.0, 0.0),
|
||||
Vector(0.0, 0.0, 1.0),
|
||||
Vector(0.0, 0.0, -1.0),
|
||||
|
||||
Vector(-1.0, -1.0, -1.0).normalize(),
|
||||
Vector(1.0, -1.0, 1.0).normalize(),
|
||||
Vector(1.0, -1.0, -1.0).normalize(),
|
||||
Vector(-1.0, -1.0, 1.0).normalize(),
|
||||
Vector(-1.0, 1.0, -1.0).normalize(),
|
||||
Vector(1.0, 1.0, 1.0).normalize(),
|
||||
Vector(1.0, 1.0, -1.0).normalize(),
|
||||
Vector(-1.0, 1.0, 1.0).normalize(),
|
||||
)
|
||||
|
||||
class ExplosionSphere(val hive: ExplosionSphereHive, var pos: Vec3, var stepVelocity: Vec3, var force: Double) {
|
||||
val initialPos = pos
|
||||
private var lastSplitPos = pos
|
||||
val level: ServerLevel get() = hive.level
|
||||
val blockPos: BlockPos get() = BlockPos(round(pos.x), round(pos.y), round(pos.z))
|
||||
|
||||
fun travelled(): Double {
|
||||
return pos.distanceTo(initialPos)
|
||||
}
|
||||
|
||||
private fun travelledFromLastSplit(): Double {
|
||||
return pos.distanceTo(lastSplitPos)
|
||||
}
|
||||
|
||||
fun step(): Boolean {
|
||||
if (force <= 0.0) {
|
||||
return false
|
||||
}
|
||||
|
||||
val blockPos = blockPos
|
||||
|
||||
for (point in sphere) {
|
||||
val finalPos = blockPos + point
|
||||
val block = level.getBlockState(finalPos)
|
||||
|
||||
if (!block.isAir && block.block !is BlockExplosionDebugger) {
|
||||
val explosion = Explosion(level, null, null, null, pos.x, pos.y, pos.z, force.toFloat(),false, Explosion.BlockInteraction.BREAK)
|
||||
val explosionResistance = block.getExplosionResistance(level, blockPos, explosion)
|
||||
|
||||
if (explosionResistance > force) {
|
||||
// поглощено
|
||||
// TODO: вместо полного поглощения отражение
|
||||
force = 0.0
|
||||
return false
|
||||
} else {
|
||||
// взорвано
|
||||
force -= explosionResistance
|
||||
|
||||
// TODO: дропы когда будет добавлена более общая версия
|
||||
level.setBlock(blockPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pos += stepVelocity
|
||||
|
||||
force -= 0.4
|
||||
|
||||
if (travelledFromLastSplit() >= TRAVEL_TO_SPLIT && force >= 10) {
|
||||
force /= 2.0
|
||||
|
||||
val up = stepVelocity.up()
|
||||
val left = stepVelocity.left()
|
||||
|
||||
val a = stepVelocity.rotateAroundAxis(up, Math.PI / 4)
|
||||
val b = stepVelocity.rotateAroundAxis(up, -Math.PI / 4)
|
||||
val c = stepVelocity.rotateAroundAxis(left, Math.PI / 4)
|
||||
val d = stepVelocity.rotateAroundAxis(left, -Math.PI / 4)
|
||||
|
||||
hive.addRay(pos, a, force)
|
||||
hive.addRay(pos, b, force)
|
||||
hive.addRay(pos, c, force)
|
||||
hive.addRay(pos, d, force)
|
||||
|
||||
lastSplitPos = pos
|
||||
}
|
||||
|
||||
return force > 0.0
|
||||
}
|
||||
|
||||
fun serializeNbt(): CompoundTag {
|
||||
return CompoundTag()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TRAVEL_TO_SPLIT = 4.0
|
||||
|
||||
fun deserializeNbt(hive: ExplosionSphereHive, tag: CompoundTag): ExplosionSphere {
|
||||
return ExplosionSphere(hive, Vector.ZERO, Vector.ZERO, 0.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ExplosionSphereHive(val level: ServerLevel) {
|
||||
private val spheres = ArrayList<ExplosionSphere>()
|
||||
|
||||
var stepNumber = 0
|
||||
private set
|
||||
|
||||
fun addRay(pos: Vec3, stepVelocity: Vec3, force: Double) {
|
||||
spheres.add(ExplosionSphere(this, pos, stepVelocity, force))
|
||||
}
|
||||
|
||||
fun addDefaultRays(pos: Vec3, force: Double) {
|
||||
for (stepVelocity in initialDirections) {
|
||||
addRay(pos, stepVelocity, force * 8)
|
||||
}
|
||||
}
|
||||
|
||||
fun step() {
|
||||
stepNumber++
|
||||
|
||||
val toRemove = ArrayList<Int>()
|
||||
|
||||
for (i in 0 until spheres.size) {
|
||||
if (!spheres[i].step()) {
|
||||
toRemove.add(i)
|
||||
}
|
||||
}
|
||||
|
||||
for (i in toRemove.size - 1 downTo 0) {
|
||||
spheres.removeAt(toRemove[i])
|
||||
}
|
||||
}
|
||||
|
||||
fun serializeNbt(): CompoundTag {
|
||||
return CompoundTag().also {
|
||||
it["spheres"] = ListTag().also {
|
||||
for (ray in spheres)
|
||||
it.add(ray.serializeNbt())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deserializeNbt(tag: CompoundTag) {
|
||||
(tag["spheres"] as? ListTag)?.also {
|
||||
for (elem in it) {
|
||||
spheres.add(ExplosionSphere.deserializeNbt(this, elem as CompoundTag))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isEmpty(): Boolean {
|
||||
return spheres.isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
class ExplosionRay(val hive: ExplosionRayHive, var pos: Vec3, var stepVelocity: Vec3, var force: Double) {
|
||||
val initialPos = pos
|
||||
private var lastSplitPos = pos
|
||||
val level: ServerLevel get() = hive.level
|
||||
val blockPos: BlockPos get() = BlockPos(round(pos.x), round(pos.y), round(pos.z))
|
||||
private var prev: MutableInt? = null
|
||||
|
||||
fun travelled(): Double {
|
||||
return pos.distanceTo(initialPos)
|
||||
}
|
||||
|
||||
private fun travelledFromLastSplit(): Double {
|
||||
return pos.distanceTo(lastSplitPos)
|
||||
}
|
||||
|
||||
fun step(spread: Boolean): Boolean {
|
||||
if (force <= 0.0) {
|
||||
return false
|
||||
}
|
||||
|
||||
val blockPos = blockPos
|
||||
|
||||
if (!level.isInWorldBounds(blockPos))
|
||||
return false
|
||||
|
||||
// val chunk = level.chunkSource.getChunkNow(SectionPos.blockToSectionCoord(blockPos.x), SectionPos.blockToSectionCoord(blockPos.z)) ?: return true
|
||||
val block = level.getBlockState(blockPos)
|
||||
|
||||
if (!block.isAir && block.block !is BlockExplosionDebugger) {
|
||||
val explosion = Explosion(level, null, null, null, pos.x, pos.y, pos.z, force.toFloat(),false, Explosion.BlockInteraction.BREAK)
|
||||
val explosionResistance = block.getExplosionResistance(level, blockPos, explosion)
|
||||
|
||||
if (explosionResistance > force) {
|
||||
// поглощено
|
||||
// TODO: вместо полного поглощения отражение
|
||||
force = 0.0
|
||||
return false
|
||||
} else {
|
||||
// взорвано
|
||||
force -= explosionResistance
|
||||
|
||||
// TODO: дропы когда будет добавлена более общая версия
|
||||
level.setBlock(blockPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL)
|
||||
}
|
||||
}
|
||||
|
||||
val old = this.blockPos
|
||||
pos += stepVelocity
|
||||
val new = this.blockPos
|
||||
|
||||
if (old != new) {
|
||||
val prev = prev
|
||||
|
||||
if (prev != null) {
|
||||
prev.dec()
|
||||
|
||||
if (prev.value <= 0) {
|
||||
hive.checkKey(old)
|
||||
}
|
||||
}
|
||||
|
||||
this.prev = hive.incDensity(new)
|
||||
}
|
||||
|
||||
force -= 0.4
|
||||
|
||||
if (spread && travelledFromLastSplit() >= TRAVEL_TO_SPLIT * sqrt(travelled() / 9.0) && force >= 10) {
|
||||
force /= 2.0
|
||||
|
||||
val up = stepVelocity.up()
|
||||
val left = stepVelocity.left()
|
||||
|
||||
val a = stepVelocity.rotateAroundAxis(up, Math.PI / 5.5)
|
||||
val b = stepVelocity.rotateAroundAxis(up, -Math.PI / 5.5)
|
||||
val c = stepVelocity.rotateAroundAxis(left, Math.PI / 5.5)
|
||||
val d = stepVelocity.rotateAroundAxis(left, -Math.PI / 5.5)
|
||||
|
||||
hive.addRay(pos, a, force)
|
||||
hive.addRay(pos, b, force)
|
||||
hive.addRay(pos, c, force)
|
||||
hive.addRay(pos, d, force)
|
||||
|
||||
lastSplitPos = pos
|
||||
}
|
||||
|
||||
return force > 0f
|
||||
}
|
||||
|
||||
fun serializeNbt(): CompoundTag {
|
||||
return CompoundTag().also {
|
||||
it["pos"] = ListTag().also {
|
||||
it.add(DoubleTag.valueOf(pos.x))
|
||||
it.add(DoubleTag.valueOf(pos.y))
|
||||
it.add(DoubleTag.valueOf(pos.z))
|
||||
}
|
||||
|
||||
it["stepVelocity"] = ListTag().also {
|
||||
it.add(DoubleTag.valueOf(stepVelocity.x))
|
||||
it.add(DoubleTag.valueOf(stepVelocity.y))
|
||||
it.add(DoubleTag.valueOf(stepVelocity.z))
|
||||
}
|
||||
|
||||
it["force"] = force
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TRAVEL_TO_SPLIT = 4.0
|
||||
|
||||
fun deserializeNbt(hive: ExplosionRayHive, tag: CompoundTag): ExplosionRay {
|
||||
val pos = tag["pos"] as ListTag
|
||||
val stepVelocity = tag["stepVelocity"] as ListTag
|
||||
|
||||
return ExplosionRay(hive,
|
||||
Vector((pos[0] as DoubleTag).asDouble, (pos[1] as DoubleTag).asDouble, (pos[2] as DoubleTag).asDouble),
|
||||
Vector((stepVelocity[0] as DoubleTag).asDouble, (stepVelocity[1] as DoubleTag).asDouble, (stepVelocity[2] as DoubleTag).asDouble),
|
||||
(tag["force"] as DoubleTag).asDouble
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class MutableInt(var value: Int = 0) {
|
||||
fun inc() {value++}
|
||||
fun dec() {value--}
|
||||
fun zero() = value <= 0
|
||||
}
|
||||
|
||||
class ExplosionRayHive(val level: ServerLevel) {
|
||||
private val rays = ArrayList<ExplosionRay>()
|
||||
private val densityMap = HashMap<BlockPos, MutableInt>()
|
||||
var stepNumber = 0
|
||||
private set
|
||||
|
||||
fun incDensity(pos: BlockPos): MutableInt {
|
||||
return densityMap.computeIfAbsent(pos) {MutableInt()}.also(MutableInt::inc)
|
||||
}
|
||||
|
||||
fun decDensity(pos: BlockPos) {
|
||||
val value = densityMap.computeIfAbsent(pos) {MutableInt()}
|
||||
value.dec()
|
||||
|
||||
if (value.zero()) {
|
||||
densityMap.remove(pos)
|
||||
}
|
||||
}
|
||||
|
||||
fun checkKey(pos: BlockPos) {
|
||||
val value = densityMap.computeIfAbsent(pos) {MutableInt()}
|
||||
|
||||
if (value.zero()) {
|
||||
densityMap.remove(pos)
|
||||
}
|
||||
}
|
||||
|
||||
fun addRay(pos: Vec3, stepVelocity: Vec3, force: Double) {
|
||||
rays.add(ExplosionRay(this, pos, stepVelocity, force))
|
||||
}
|
||||
|
||||
fun step() {
|
||||
stepNumber++
|
||||
|
||||
val toRemove = ArrayList<Int>()
|
||||
val density = calculateDensity()
|
||||
|
||||
for (i in 0 until rays.size) {
|
||||
if (!rays[i].step(density < 3.0)) {
|
||||
toRemove.add(i)
|
||||
decDensity(rays[i].blockPos)
|
||||
}
|
||||
}
|
||||
|
||||
for (i in toRemove.size - 1 downTo 0) {
|
||||
rays.removeAt(toRemove[i])
|
||||
}
|
||||
|
||||
if (stepNumber % 4 == 0) {
|
||||
LOGGER.info("At step {} density of hive {} with {} elements is {}", stepNumber, this, rays.size, density)
|
||||
}
|
||||
}
|
||||
|
||||
fun calculateDensity(): Double {
|
||||
return rays.size.toDouble() / densityMap.size
|
||||
}
|
||||
|
||||
fun serializeNbt(): CompoundTag {
|
||||
return CompoundTag().also {
|
||||
it["rays"] = ListTag().also {
|
||||
for (ray in rays)
|
||||
it.add(ray.serializeNbt())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun deserializeNbt(tag: CompoundTag) {
|
||||
(tag["rays"] as? ListTag)?.also {
|
||||
for (elem in it) {
|
||||
rays.add(ExplosionRay.deserializeNbt(this, elem as CompoundTag))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isEmpty(): Boolean {
|
||||
return rays.isEmpty()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val LOGGER = LogManager.getLogger()
|
||||
private val SQUARE_5 = sqrt(5.0)
|
||||
|
||||
fun evenlyDistributedPoints(amount: Int): List<Vec3> {
|
||||
val list = ArrayList<Vec3>()
|
||||
|
||||
for (i in 0 .. amount) {
|
||||
val idx = i.toDouble() / amount
|
||||
val phi = acos(1.0 - 2.0 * idx)
|
||||
val theta = Math.PI * (1.0 + SQUARE_5) * i
|
||||
|
||||
list.add(Vec3(cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi)))
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object BlackHoleExplosionDamageCalculator : ExplosionDamageCalculator() {
|
||||
override fun getBlockExplosionResistance(
|
||||
explosion: Explosion,
|
||||
getter: BlockGetter,
|
||||
pos: BlockPos,
|
||||
state: BlockState,
|
||||
fstate: FluidState
|
||||
): Optional<Float> {
|
||||
return if (state.isAir && fstate.isEmpty) Optional.empty() else Optional.of(
|
||||
Math.sqrt(
|
||||
Math.max(
|
||||
0f,
|
||||
Math.max(
|
||||
state.getExplosionResistance(getter, pos, explosion),
|
||||
fstate.getExplosionResistance(getter, pos, explosion)
|
||||
)
|
||||
).toDouble()
|
||||
).toFloat()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private data class RingExplosion(val x: Double, val y: Double, val z: Double, val radius: Double, val strength: Float) {
|
||||
fun serializeNBT(): CompoundTag {
|
||||
return CompoundTag().also {
|
||||
it["x"] = x
|
||||
it["y"] = y
|
||||
it["z"] = z
|
||||
it["radius"] = radius
|
||||
it["strength"] = strength
|
||||
}
|
||||
}
|
||||
|
||||
fun explode(queue: ExplosionQueue) {
|
||||
for (pos in ExplosionRayHive.evenlyDistributedPoints(radius.toInt() * 80)) {
|
||||
val (x, y, z) = pos
|
||||
|
||||
queue.explode(
|
||||
this.x + x * radius * 15,
|
||||
this.y + y * radius * 15,
|
||||
this.z + z * radius * 15,
|
||||
strength
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun deserializeNBT(tag: CompoundTag): RingExplosion {
|
||||
return RingExplosion(
|
||||
tag.getDouble("x"),
|
||||
tag.getDouble("y"),
|
||||
tag.getDouble("z"),
|
||||
tag.getDouble("radius"),
|
||||
tag.getFloat("strength")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private data class QueuedExplosion(val x: Double, val y: Double, val z: Double, val radius: Float) {
|
||||
fun serializeNBT(): CompoundTag {
|
||||
return CompoundTag().also {
|
||||
it["x"] = x
|
||||
it["y"] = y
|
||||
it["z"] = z
|
||||
it["radius"] = radius
|
||||
}
|
||||
}
|
||||
|
||||
fun explode(level: Level) {
|
||||
level.explode(
|
||||
null,
|
||||
Registry.DAMAGE_HAWKING_RADIATION,
|
||||
BlackHoleExplosionDamageCalculator,
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
radius,
|
||||
false,
|
||||
Explosion.BlockInteraction.DESTROY
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun deserializeNBT(tag: CompoundTag): QueuedExplosion {
|
||||
return QueuedExplosion(tag.getDouble("x"), tag.getDouble("y"), tag.getDouble("z"), tag.getFloat("radius"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ExplosionQueue(private val level: ServerLevel) : SavedData() {
|
||||
private var indexExplosion = 0
|
||||
private var indexRing = 0
|
||||
private val explosions = ArrayList<QueuedExplosion>()
|
||||
private val rings = ArrayList<RingExplosion>()
|
||||
private val hives = ArrayList<ExplosionRayHive>()
|
||||
|
||||
override fun save(tag: CompoundTag): CompoundTag {
|
||||
val listExplosions = ListTag()
|
||||
val listRings = ListTag()
|
||||
|
||||
for (i in indexExplosion until explosions.size)
|
||||
listExplosions.add(explosions[i].serializeNBT())
|
||||
|
||||
for (i in indexRing until rings.size)
|
||||
listRings.add(rings[i].serializeNBT())
|
||||
|
||||
tag["explosions"] = listExplosions
|
||||
tag["rings"] = listRings
|
||||
// tag["hives"] = ListTag().also {
|
||||
// for (hive in hives) {
|
||||
// it.add(hive.serializeNbt())
|
||||
// }
|
||||
// }
|
||||
|
||||
return tag
|
||||
}
|
||||
|
||||
fun load(tag: CompoundTag) {
|
||||
explosions.clear()
|
||||
rings.clear()
|
||||
hives.clear()
|
||||
|
||||
indexExplosion = 0
|
||||
indexRing = 0
|
||||
|
||||
for (explosion in tag.getList("explosions", Tag.TAG_COMPOUND.toInt()))
|
||||
explosions.add(QueuedExplosion.deserializeNBT(explosion as CompoundTag))
|
||||
|
||||
for (ring in tag.getList("rings", Tag.TAG_COMPOUND.toInt()))
|
||||
rings.add(RingExplosion.deserializeNBT(ring as CompoundTag))
|
||||
|
||||
for (hive in tag.getList("hives", Tag.TAG_COMPOUND.toInt()))
|
||||
hives.add(ExplosionRayHive(level).also { it.deserializeNbt(hive as CompoundTag) })
|
||||
}
|
||||
|
||||
fun explode(x: Double, y: Double, z: Double, radius: Float) {
|
||||
if (level.isOutsideBuildHeight(BlockPos(x, y + 24, z)) || level.isOutsideBuildHeight(BlockPos(x, y - 24, z)))
|
||||
return
|
||||
|
||||
explosions.add(QueuedExplosion(x, y, z, radius))
|
||||
isDirty = true
|
||||
}
|
||||
|
||||
fun explodeRing(x: Double, y: Double, z: Double, radius: Double, strength: Float) {
|
||||
rings.add(RingExplosion(x, y, z, radius, strength))
|
||||
isDirty = true
|
||||
}
|
||||
|
||||
fun explodeRays(tpos: Vector, force: Double) {
|
||||
val hive = ExplosionRayHive(level)
|
||||
hives.add(hive)
|
||||
|
||||
for (normal in ExplosionRayHive.evenlyDistributedPoints(1000)) {
|
||||
hive.addRay(normal + tpos, normal, force)
|
||||
}
|
||||
|
||||
isDirty = true
|
||||
}
|
||||
|
||||
fun tick() {
|
||||
if (explosions.size != 0) {
|
||||
isDirty = true
|
||||
var iterations = 0
|
||||
|
||||
for (i in indexExplosion until explosions.size) {
|
||||
explosions[i].explode(level)
|
||||
indexExplosion++
|
||||
|
||||
if (iterations++ == 4) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (indexExplosion >= explosions.size) {
|
||||
indexExplosion = 0
|
||||
explosions.clear()
|
||||
}
|
||||
} else if (rings.size != 0) {
|
||||
if (indexRing >= rings.size) {
|
||||
indexRing = 0
|
||||
rings.clear()
|
||||
} else {
|
||||
rings[indexRing++].explode(this)
|
||||
}
|
||||
}
|
||||
|
||||
for (i in hives.size - 1 downTo 0) {
|
||||
isDirty = true
|
||||
hives[i].step()
|
||||
|
||||
if (hives[i].isEmpty()) {
|
||||
hives.removeAt(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun queueForLevel(level: ServerLevel): ExplosionQueue {
|
||||
return level.dataStorage.computeIfAbsent(
|
||||
{
|
||||
val factory = ExplosionQueue(level)
|
||||
factory.load(it)
|
||||
factory
|
||||
},
|
||||
{ ExplosionQueue(level) },
|
||||
"otm_blackhole_explosion_queue"
|
||||
)
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
fun onWorldTick(event: TickEvent.WorldTickEvent) {
|
||||
if (event.phase == TickEvent.Phase.START && event.world is ServerLevel) {
|
||||
queueForLevel(event.world as ServerLevel).tick()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
115
src/main/kotlin/ru/dbotthepony/mc/otm/core/Math.kt
Normal file
115
src/main/kotlin/ru/dbotthepony/mc/otm/core/Math.kt
Normal file
@ -0,0 +1,115 @@
|
||||
package ru.dbotthepony.mc.otm.core
|
||||
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.core.Vec3i
|
||||
import net.minecraft.world.phys.Vec3
|
||||
import kotlin.math.sin
|
||||
import kotlin.math.cos
|
||||
import kotlin.math.acos
|
||||
|
||||
typealias Vector = Vec3
|
||||
|
||||
val VECTOR_UP = Vector(0.0, 1.0, 0.0)
|
||||
val VECTOR_DOWN = Vector(0.0, -1.0, 0.0)
|
||||
val VECTOR_BACK = Vector(0.0, 0.0, 1.0)
|
||||
|
||||
fun BlockPos.asVector(): Vector {
|
||||
return Vector(x + 0.5, y + 0.5, z + 0.5)
|
||||
}
|
||||
|
||||
fun Vector.asAngle(): Angle {
|
||||
val norm = normalize()
|
||||
|
||||
if (norm.x < 0) {
|
||||
return Angle(acos(norm.dot(VECTOR_UP)) - Angle.PI_HALF, -acos(Vector(norm.x, 0.0, norm.z).normalize().dot(VECTOR_BACK)))
|
||||
}
|
||||
|
||||
return Angle(acos(norm.dot(VECTOR_UP)) - Angle.PI_HALF, acos(Vector(norm.x, 0.0, norm.z).normalize().dot(VECTOR_BACK)))
|
||||
}
|
||||
|
||||
operator fun BlockPos.plus(direction: Vec3i): BlockPos = this.offset(direction)
|
||||
operator fun BlockPos.plus(direction: Direction): BlockPos = this.offset(direction.normal)
|
||||
operator fun BlockPos.minus(direction: Vec3i): BlockPos = this.subtract(direction)
|
||||
operator fun BlockPos.minus(direction: Direction): BlockPos = this.subtract(direction.normal)
|
||||
|
||||
operator fun Vec3i.plus(direction: Vec3i): Vec3i = this.offset(direction)
|
||||
operator fun Vec3i.plus(direction: Direction): Vec3i = this.offset(direction.normal)
|
||||
operator fun Vec3i.minus(direction: Vec3i): Vec3i = this.subtract(direction)
|
||||
operator fun Vec3i.minus(direction: Direction): Vec3i = this.subtract(direction.normal)
|
||||
|
||||
operator fun Vector.plus(direction: Vector): Vector = this.add(direction)
|
||||
operator fun Vector.minus(direction: Vector): Vector = this.subtract(direction)
|
||||
|
||||
operator fun Vector.times(v: Double): Vector = this.multiply(v, v, v)
|
||||
|
||||
fun Vector.left() = asAngle().left() * this.length()
|
||||
fun Vector.right() = asAngle().right() * this.length()
|
||||
fun Vector.up() = asAngle().up() * this.length()
|
||||
fun Vector.down() = asAngle().down() * this.length()
|
||||
|
||||
fun Vector.rotateAroundAxis(axis: Vector, rotation: Double): Vector {
|
||||
return this * cos(rotation) + axis.cross(this) * sin(rotation) + axis * axis.dot(this) * (1 - cos(rotation))
|
||||
}
|
||||
|
||||
operator fun Vector.component1() = x
|
||||
operator fun Vector.component2() = y
|
||||
operator fun Vector.component3() = z
|
||||
|
||||
data class Angle(val pitch: Double = 0.0, val yaw: Double = 0.0, val roll: Double = 0.0) {
|
||||
fun forward(): Vector {
|
||||
val yaw = yaw - PI_HALF
|
||||
val x = cos(yaw) * cos(pitch)
|
||||
val y = -sin(pitch)
|
||||
val z = sin(yaw) * cos(pitch)
|
||||
|
||||
return Vector(x, y, z)
|
||||
}
|
||||
|
||||
fun right(): Vector {
|
||||
val pitch = 0.0
|
||||
val x = cos(yaw) * cos(pitch)
|
||||
val y = -sin(pitch)
|
||||
val z = sin(yaw) * cos(pitch)
|
||||
|
||||
return Vector(x, y, z)
|
||||
}
|
||||
|
||||
fun left(): Vector {
|
||||
val yaw = yaw + PI_HALF
|
||||
val pitch = 0.0
|
||||
val x = cos(yaw) * cos(pitch)
|
||||
val y = -sin(pitch)
|
||||
val z = sin(yaw) * cos(pitch)
|
||||
|
||||
return Vector(x, y, z)
|
||||
}
|
||||
|
||||
fun up(): Vector {
|
||||
val yaw = yaw - PI_HALF
|
||||
val pitch = pitch - PI_HALF
|
||||
val x = cos(yaw) * cos(pitch)
|
||||
val y = -sin(pitch)
|
||||
val z = sin(yaw) * cos(pitch)
|
||||
|
||||
return Vector(x, y, z)
|
||||
}
|
||||
|
||||
fun down(): Vector {
|
||||
val yaw = yaw - PI_HALF
|
||||
val pitch = pitch + PI_HALF
|
||||
val x = cos(yaw) * cos(pitch)
|
||||
val y = -sin(pitch)
|
||||
val z = sin(yaw) * cos(pitch)
|
||||
|
||||
return Vector(x, y, z)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val PI_HALF = Math.PI / 2.0
|
||||
|
||||
fun degrees(pitch: Double, yaw: Double, roll: Double): Angle {
|
||||
return Angle(Math.toDegrees(pitch), Math.toDegrees(yaw), Math.toDegrees(roll))
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ import net.minecraft.core.SectionPos
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.level.block.entity.BlockEntity
|
||||
import ru.dbotthepony.mc.otm.OverdriveThatMatters
|
||||
import ru.dbotthepony.mc.otm.plus
|
||||
import ru.dbotthepony.mc.otm.core.plus
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user