Initial attempt at chunkloading explosions

This fixes a bug where leaving the chunk shortly after an explosion will
cause the explosion to either not happen, or do very little.

Currently this functionality only applies to nuclear explosions.

When the EntityNuclearExplosion does its first tick we grab a ticket
from ForgeChunkManager and use it to load the chunk that will contain
the EntityFalloutRain. The ticket is then passed to the
EntityFalloutRain which will unload the chunk when it finishes its work.

Doing it this way will almost certianly add race conditions but it works
as a proof of concept. Ideally I imagine we would wnat to have some
class that will keep track of loaded explosions and make sure that they
are unloaded properly even if the entity somehow despawns.

I also did not impliment anything in the chunk loading callback. As far
as I understand, we would need to store the loaded chunks there so if
the server dies in the middle of an explosion, it will be reloaded when
the server comes back up.
This commit is contained in:
Thomas Muller 2021-10-21 20:55:56 -04:00
parent d8d09ec90c
commit aad46297f4
Signed by: thomas
GPG key ID: AF006EB730564952
4 changed files with 74 additions and 4 deletions

View file

@ -11,10 +11,12 @@ import trinity.gui.GuiHandlerRegistry;
import trinity.init.ModBlocks; import trinity.init.ModBlocks;
import trinity.init.TrinityRecipes; import trinity.init.TrinityRecipes;
import trinity.radiation.RadiationHandler; import trinity.radiation.RadiationHandler;
import trinity.world.ChunkLoader;
import net.minecraft.item.Item; import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
//import nca.worldgen.OreGen; //import nca.worldgen.OreGen;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.ForgeChunkManager;
import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
@ -59,6 +61,7 @@ public class Trinity {
TCLoaded = Loader.isModLoaded("thaumcraft"); TCLoaded = Loader.isModLoaded("thaumcraft");
ICBMLoaded = Loader.isModLoaded("icbmclassic"); ICBMLoaded = Loader.isModLoaded("icbmclassic");
QMDLoaded = Loader.isModLoaded("qmd"); QMDLoaded = Loader.isModLoaded("qmd");
ForgeChunkManager.setForcedChunkLoadingCallback(Trinity.instance, ChunkLoader.getInstance());
TrinityConfig.preInit(); TrinityConfig.preInit();
proxy.preInit(preEvent); proxy.preInit(preEvent);
proxy.registerRenderInfo(); proxy.registerRenderInfo();

View file

@ -33,6 +33,7 @@ import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.BlockPos.MutableBlockPos; import net.minecraft.util.math.BlockPos.MutableBlockPos;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
//import net.minecraft.util.AxisAlignedBB; //import net.minecraft.util.AxisAlignedBB;
@ -44,6 +45,7 @@ import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.fluids.BlockFluidClassic; import net.minecraftforge.fluids.BlockFluidClassic;
import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.common.ForgeChunkManager;
//import thaumcraft.api.aura.AuraHelper; //import thaumcraft.api.aura.AuraHelper;
//import thaumcraft.api.blocks.BlocksTC; //import thaumcraft.api.blocks.BlocksTC;
import trinity.Trinity; import trinity.Trinity;
@ -67,6 +69,9 @@ public class EntityFalloutRain extends Entity implements INuclearEffect {
private boolean salted; private boolean salted;
private boolean thermonuclear; private boolean thermonuclear;
private ForgeChunkManager.Ticket ticket = null;
private boolean isChunkLoaded = false;
public EntityFalloutRain(World p_i1582_1_) { public EntityFalloutRain(World p_i1582_1_) {
super(p_i1582_1_); super(p_i1582_1_);
this.setSize(4, 20); this.setSize(4, 20);
@ -106,7 +111,12 @@ public class EntityFalloutRain extends Entity implements INuclearEffect {
return bb; return bb;
//return this.getEntityBoundingBox(); //return this.getEntityBoundingBox();
} }
public void setChunkTicket(ForgeChunkManager.Ticket ticket) {
this.ticket = ticket;
isChunkLoaded = true;
}
@Override @Override
public void onUpdate() { public void onUpdate() {
@ -156,7 +166,14 @@ public class EntityFalloutRain extends Entity implements INuclearEffect {
} }
if(radProgress > getScale() * 2D) { if(radProgress > getScale() * 2D) {
if(isChunkLoaded && !this.world.isRemote && ticket != null) {
int chunkX = (int)Math.floor(this.posX) >> 4;
int chunkZ = (int)Math.floor(this.posZ) >> 4;
// System.out.println(ticket + " being unloaded for " + chunkX + ", " + chunkZ);
ForgeChunkManager.unforceChunk(ticket, new ChunkPos(chunkX, chunkZ));
ForgeChunkManager.releaseTicket(ticket);
isChunkLoaded = false;
}
this.setDead(); this.setDead();
} }
} }

View file

@ -2,6 +2,7 @@ package trinity.entities;
import org.apache.logging.log4j.Level; import org.apache.logging.log4j.Level;
import trinity.Trinity;
import trinity.config.TrinityConfig; import trinity.config.TrinityConfig;
import trinity.entities.EntityFalloutRain; import trinity.entities.EntityFalloutRain;
//import trinity.explosion.ExplosionHyperspace; //import trinity.explosion.ExplosionHyperspace;
@ -18,7 +19,9 @@ import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.SoundCategory; import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent; import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.common.ForgeChunkManager;
public class EntityNuclearExplosion extends Entity { public class EntityNuclearExplosion extends Entity {
@ -35,7 +38,10 @@ public class EntityNuclearExplosion extends Entity {
public boolean thermal = true; public boolean thermal = true;
public boolean Void = false; public boolean Void = false;
public int chance = 0; public int chance = 0;
private ForgeChunkManager.Ticket ticket = null;
private boolean isChunkLoaded = false;
ExplosionNukeRay explosion; ExplosionNukeRay explosion;
public EntityNuclearExplosion(World p_i1582_1_) { public EntityNuclearExplosion(World p_i1582_1_) {
@ -57,7 +63,18 @@ public class EntityNuclearExplosion extends Entity {
this.setDead(); this.setDead();
return; return;
} }
if(!isChunkLoaded && !this.world.isRemote) {
int chunkX = (int)Math.floor(this.posX) >> 4;
int chunkZ = (int)Math.floor(this.posZ) >> 4;
ticket = ForgeChunkManager.requestTicket(Trinity.instance, this.world, ForgeChunkManager.Type.NORMAL);
if(ticket != null) {
// System.out.println(ticket + " being loaded for " + chunkX + ", " + chunkZ);
ForgeChunkManager.forceChunk(ticket, new ChunkPos(chunkX, chunkZ));
isChunkLoaded = true;
}
}
BlockPos pos = new BlockPos(this.posX, this.posY, this.posZ); BlockPos pos = new BlockPos(this.posX, this.posY, this.posZ);
this.world.playSound(this.posX, this.posY, this.posZ, SoundEvents.ENTITY_LIGHTNING_THUNDER, SoundCategory.AMBIENT, 10000.0F, 0.8F + this.rand.nextFloat() * 0.2F, false); this.world.playSound(this.posX, this.posY, this.posZ, SoundEvents.ENTITY_LIGHTNING_THUNDER, SoundCategory.AMBIENT, 10000.0F, 0.8F + this.rand.nextFloat() * 0.2F, false);
@ -91,6 +108,7 @@ public class EntityNuclearExplosion extends Entity {
if(thermonuclear) if(thermonuclear)
{ {
EntityFalloutRain fallout = new EntityFalloutRain(this.world); EntityFalloutRain fallout = new EntityFalloutRain(this.world);
fallout.setChunkTicket(ticket);
fallout.posX = this.posX; fallout.posX = this.posX;
fallout.posY = this.posY; fallout.posY = this.posY;
fallout.posZ = this.posZ; fallout.posZ = this.posZ;
@ -102,6 +120,7 @@ public class EntityNuclearExplosion extends Entity {
if(salted) if(salted)
{ {
EntityFalloutRain fallout = new EntityFalloutRain(this.world); EntityFalloutRain fallout = new EntityFalloutRain(this.world);
fallout.setChunkTicket(ticket);
fallout.posX = this.posX; fallout.posX = this.posX;
fallout.posY = this.posY; fallout.posY = this.posY;
fallout.posZ = this.posZ; fallout.posZ = this.posZ;
@ -112,6 +131,7 @@ public class EntityNuclearExplosion extends Entity {
else if(!salted) else if(!salted)
{ {
EntityFalloutRain fallout = new EntityFalloutRain(this.world); EntityFalloutRain fallout = new EntityFalloutRain(this.world);
fallout.setChunkTicket(ticket);
fallout.posX = this.posX; fallout.posX = this.posX;
fallout.posY = this.posY; fallout.posY = this.posY;
fallout.posZ = this.posZ; fallout.posZ = this.posZ;

View file

@ -0,0 +1,30 @@
package trinity.world;
import java.util.List;
import net.minecraft.world.World;
import com.google.common.collect.ListMultimap;
import net.minecraftforge.common.ForgeChunkManager;
public class ChunkLoader implements ForgeChunkManager.PlayerOrderedLoadingCallback {
private static ChunkLoader INSTANCE;
public static ChunkLoader getInstance() {
if (INSTANCE == null) {
INSTANCE = new ChunkLoader();
}
return INSTANCE;
}
@Override
public ListMultimap<String, ForgeChunkManager.Ticket> playerTicketsLoaded(ListMultimap<String, ForgeChunkManager.Ticket> tickets, World world) {
return tickets;
}
@Override
public void ticketsLoaded(List<ForgeChunkManager.Ticket> tickets, World world) {
}
}