From 92f1219b6a943251b89284b6c12f67fd0c6d5238 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 3 Sep 2021 15:29:46 +0700 Subject: [PATCH] Improve blackhole explosion, rendering server responsive when one is collapsing --- .../mc/otm/OverdriveThatMatters.java | 2 + .../java/ru/dbotthepony/mc/otm/Registry.java | 2 +- .../block/entity/BlockEntityBlackHole.java | 222 +++++++++++++++--- 3 files changed, 194 insertions(+), 32 deletions(-) diff --git a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java index 96d19f6d4..42d5d8d73 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java +++ b/src/main/java/ru/dbotthepony/mc/otm/OverdriveThatMatters.java @@ -12,6 +12,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.BlockEntityBlackHole; import ru.dbotthepony.mc.otm.capability.AndroidCapability; import ru.dbotthepony.mc.otm.capability.AndroidCapabilityPlayer; import ru.dbotthepony.mc.otm.capability.MatteryCapability; @@ -53,6 +54,7 @@ public class OverdriveThatMatters { MinecraftForge.EVENT_BUS.register(AndroidCapability.class); MinecraftForge.EVENT_BUS.register(MatterGrid.class); MinecraftForge.EVENT_BUS.register(MatterRegistry.class); + MinecraftForge.EVENT_BUS.register(BlockEntityBlackHole.BlackHoleExplosionQueue.class); FMLJavaModLoadingContext.get().getModEventBus().register(Registry.Items.class); FMLJavaModLoadingContext.get().getModEventBus().register(Registry.Blocks.class); diff --git a/src/main/java/ru/dbotthepony/mc/otm/Registry.java b/src/main/java/ru/dbotthepony/mc/otm/Registry.java index 61f5aff36..6ee1d26b7 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/Registry.java +++ b/src/main/java/ru/dbotthepony/mc/otm/Registry.java @@ -52,7 +52,7 @@ public class Registry { DAMAGE_BECOME_ANDROID.bypassArmor().bypassInvul().bypassMagic(); DAMAGE_BECOME_HUMANE.bypassArmor().bypassInvul().bypassMagic(); DAMAGE_EVENT_HORIZON.bypassMagic().bypassArmor(); - DAMAGE_HAWKING_RADIATION.bypassMagic().bypassArmor(); + // DAMAGE_HAWKING_RADIATION.bypassMagic().bypassArmor(); } public static final ForgeRegistry> ANDROID_FEATURES; diff --git a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityBlackHole.java b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityBlackHole.java index a9ed3da74..b29d8e861 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityBlackHole.java +++ b/src/main/java/ru/dbotthepony/mc/otm/block/entity/BlockEntityBlackHole.java @@ -3,10 +3,13 @@ package ru.dbotthepony.mc.otm.block.entity; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; import net.minecraft.network.Connection; import net.minecraft.network.protocol.PacketFlow; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; +import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.item.ItemEntity; @@ -21,8 +24,11 @@ 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.OverdriveThatMatters; import ru.dbotthepony.mc.otm.Registry; import ru.dbotthepony.mc.otm.capability.MatteryCapability; @@ -30,6 +36,7 @@ import ru.dbotthepony.mc.otm.matter.MatterRegistry; import javax.annotation.Nullable; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Optional; public class BlockEntityBlackHole extends BlockEntity { @@ -67,6 +74,179 @@ public class BlockEntityBlackHole extends BlockEntity { private static final BlackHoleExplosionDamageCalculator INSTANCE = new BlackHoleExplosionDamageCalculator(); } + public static class BlackHoleExplosionQueue extends SavedData { + private record QueuedExplosion(double x, double y, double z, float radius) { + public CompoundTag serializeNBT() { + var tag = new CompoundTag(); + + tag.putDouble("x", x); + tag.putDouble("y", y); + tag.putDouble("z", z); + tag.putFloat("radius", radius); + + return tag; + } + + public static QueuedExplosion deserializeNBT(CompoundTag tag) { + return new QueuedExplosion(tag.getDouble("x"), tag.getDouble("y"), tag.getDouble("z"), tag.getFloat("radius")); + } + + public void explode(Level level) { + level.explode( + null, + Registry.DAMAGE_HAWKING_RADIATION, + BlackHoleExplosionDamageCalculator.INSTANCE, + x, + y, + z, + radius, + false, + Explosion.BlockInteraction.DESTROY); + } + } + + private record RingExplosion(double x, double y, double z, double radius, float strength) { + public CompoundTag serializeNBT() { + var tag = new CompoundTag(); + + tag.putDouble("x", x); + tag.putDouble("y", y); + tag.putDouble("z", z); + tag.putDouble("radius", radius); + + return tag; + } + + public static RingExplosion deserializeNBT(CompoundTag tag) { + return new RingExplosion(tag.getDouble("x"), tag.getDouble("y"), tag.getDouble("z"), tag.getDouble("radius"), tag.getFloat("strength")); + } + + public void explode(BlackHoleExplosionQueue queue) { + final int fragments = (int) radius * 8; + + final double stack_step = Math.PI / (double) fragments; + final double sector_step = Math.PI / (double) fragments * 2; + + for (int stack = 0; stack < fragments; stack++) { + final double stack_angle = Math.PI / 2 - stack * stack_step; + final double xy = radius * 15 * Math.cos(stack_angle); + final double z = radius * 15 * Math.sin(stack_angle); + + for (int sector = 0; sector < fragments; sector++) { + final double sector_angle = sector * sector_step; + + queue.explode( + this.x + xy * Math.cos(sector_angle), + this.y + xy * Math.sin(sector_angle), + this.z + z, + strength + ); + } + } + } + } + + private int index = 0; + private int index_ring = 0; + private final ArrayList explosions = new ArrayList<>(); + private final ArrayList rings = new ArrayList<>(); + private final ServerLevel level; + + public BlackHoleExplosionQueue(ServerLevel level) { + this.level = level; + } + + @Override + public CompoundTag save(CompoundTag tag) { + var list = new ListTag(); + var list_rings = new ListTag(); + + for (int i = index; i < explosions.size(); i++) + list.add(explosions.get(i).serializeNBT()); + + for (int i = index_ring; i < rings.size(); i++) + list_rings.add(rings.get(i).serializeNBT()); + + tag.put("explosions", list); + tag.put("rings", list_rings); + + return tag; + } + + public void load(CompoundTag tag) { + explosions.clear(); + rings.clear(); + index = 0; + index_ring = 0; + + for (var explosion : tag.getList("explosions", Tag.TAG_COMPOUND)) + explosions.add(QueuedExplosion.deserializeNBT((CompoundTag) explosion)); + + for (var ring : tag.getList("rings", Tag.TAG_COMPOUND)) + rings.add(RingExplosion.deserializeNBT((CompoundTag) ring)); + } + + public static BlackHoleExplosionQueue factory(ServerLevel level) { + return level.getDataStorage().computeIfAbsent( + (tag) -> { + var factory = new BlackHoleExplosionQueue(level); + factory.load(tag); + return factory; + }, + + () -> new BlackHoleExplosionQueue(level), + + "otm_blackhole_explosion_queue" + ); + } + + public void explode(double x, double y, double z, float radius) { + explosions.add(new QueuedExplosion(x, y, z, radius)); + setDirty(); + } + + public void explodeRing(double x, double y, double z, double radius, float strength) { + rings.add(new RingExplosion(x, y, z, radius, strength)); + setDirty(); + } + + public void tick() { + if (explosions.size() != 0) { + setDirty(); + + int iterations = 0; + + for (int i = index; i < explosions.size(); i++) { + explosions.get(i).explode(level); + index++; + + if (iterations++ == 4) { + break; + } + } + + if (index >= explosions.size()) { + index = 0; + explosions.clear(); + } + } else if (rings.size() != 0) { + if (index_ring >= rings.size()) { + index_ring = 0; + rings.clear(); + } else { + rings.get(index_ring++).explode(this); + } + } + } + + @SubscribeEvent + public static void onWorldTick(TickEvent.WorldTickEvent event) { + if (event.phase == TickEvent.Phase.START && event.world instanceof ServerLevel level) { + factory(level).tick(); + } + } + } + public void collapse() { level.setBlock(getBlockPos(), Blocks.AIR.defaultBlockState(), Block.UPDATE_ALL); @@ -75,44 +255,24 @@ public class BlockEntityBlackHole extends BlockEntity { final double y0 = getBlockPos().getY() + 0.5; final double z0 = getBlockPos().getZ() + 0.5; + var queue = BlackHoleExplosionQueue.factory((ServerLevel) level); + for (int radius = 0; radius < Math.ceil(gravitation_strength * 4); radius++) { - final int fragments = radius * 8; - - final double stack_step = Math.PI / (double) fragments; - final double sector_step = Math.PI / (double) fragments * 2; - - for (int stack = 0; stack < fragments; stack++) { - final double stack_angle = Math.PI / 2 - stack * stack_step; - final double xy = radius * 20 * Math.cos(stack_angle); - final double z = radius * 20 * Math.sin(stack_angle); - - for (int sector = 0; sector < fragments; sector++) { - final double sector_angle = sector * sector_step; - - final double x = xy * Math.cos(sector_angle); - final double y = xy * Math.sin(sector_angle); - - level.explode( - null, - Registry.DAMAGE_HAWKING_RADIATION, - BlackHoleExplosionDamageCalculator.INSTANCE, - x0 + x, - y0 + y, - z0 + z, - (float) Math.min(30, Math.max(1, (gravitation_strength * 4 - radius) * 30)), - false, - Explosion.BlockInteraction.DESTROY); - } - } + queue.explodeRing( + x0, + y0, + z0, + radius, + (float) Math.min(20, Math.max(1, (gravitation_strength * 4 - radius) * 20))); } } else { level.explode( null, Registry.DAMAGE_HAWKING_RADIATION, null, - (double)getBlockPos().getX() + 0.5D, - (double)getBlockPos().getY() + 0.5D, - (double)getBlockPos().getZ() + 0.5D, + getBlockPos().getX() + 0.5D, + getBlockPos().getY() + 0.5D, + getBlockPos().getZ() + 0.5D, (float) gravitation_strength * 60, false, Explosion.BlockInteraction.DESTROY);