Improve blackhole explosion, rendering server responsive when one is collapsing

This commit is contained in:
DBotThePony 2021-09-03 15:29:46 +07:00
parent 0d3e7c4112
commit 92f1219b6a
Signed by: DBot
GPG Key ID: DCC23B5715498507
3 changed files with 194 additions and 32 deletions

View File

@ -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);

View File

@ -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<AndroidFeatureType<?>> ANDROID_FEATURES;

View File

@ -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<QueuedExplosion> explosions = new ArrayList<>();
private final ArrayList<RingExplosion> 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);