From 5010f8812b9685f55e920feaef52d04ec44a119b Mon Sep 17 00:00:00 2001 From: Bob Date: Mon, 10 Jun 2024 22:08:40 +0200 Subject: [PATCH] PRISM pt. 2 --- .../radiation/ChunkRadiationHandlerPRISM.java | 142 ++++++++++++++++-- .../radiation/ChunkRadiationManager.java | 2 +- 2 files changed, 133 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/hbm/handler/radiation/ChunkRadiationHandlerPRISM.java b/src/main/java/com/hbm/handler/radiation/ChunkRadiationHandlerPRISM.java index 4bb894e3b..96a1bc9fa 100644 --- a/src/main/java/com/hbm/handler/radiation/ChunkRadiationHandlerPRISM.java +++ b/src/main/java/com/hbm/handler/radiation/ChunkRadiationHandlerPRISM.java @@ -1,17 +1,22 @@ package com.hbm.handler.radiation; import java.util.HashMap; +import java.util.Iterator; import java.util.Map.Entry; import com.hbm.lib.Library; import net.minecraft.block.Block; +import net.minecraft.block.material.Material; import net.minecraft.util.MathHelper; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.event.world.ChunkDataEvent; +import net.minecraftforge.event.world.ChunkEvent; +import net.minecraftforge.event.world.WorldEvent; /** * The PRISM system aims to make a semi-realistic containment system with simplified and variable resistance values. @@ -25,6 +30,12 @@ import net.minecraftforge.common.util.ForgeDirection; * The system's name stems from the "gradient"-like handling of the resistance values per axis, multiple color * gradients make a rainbow, and rainbows come from prisms. Just like a prism, sub-chunks too handle the radiation * going through them differently depending on the angle of approach. + * ___ + * /\ \ + * / \ \ + * / \ \ + * / \ \ + * /________\__\ * * @author hbm * @@ -34,6 +45,9 @@ public class ChunkRadiationHandlerPRISM extends ChunkRadiationHandler { private HashMap perWorld = new HashMap(); public static final float MAX_RADIATION = 1_000_000; + private static final String NBT_KEY_CHUNK_RADIATION = "hfr_prism_radiation_"; + private static final String NBT_KEY_CHUNK_RESISTANCE = "hfr_prism_resistance_"; + private static final String NBT_KEY_CHUNK_EXISTS = "hfr_prism_exists_"; @Override public float getRadiation(World world, int x, int y, int z) { @@ -56,12 +70,18 @@ public class ChunkRadiationHandlerPRISM extends ChunkRadiationHandler { @Override public void setRadiation(World world, int x, int y, int z, float rad) { + if(Float.isNaN(rad)) rad = 0; + RadPerWorld system = perWorld.get(world); if(system != null) { ChunkCoordIntPair coords = new ChunkCoordIntPair(x >> 4, z >> 4); int yReg = MathHelper.clamp_int(y >> 4, 0, 15); SubChunk[] subChunks = system.radiation.get(coords); + if(subChunks == null) { + subChunks = new SubChunk[16]; + system.radiation.put(coords, subChunks); + } if(subChunks[yReg] == null) subChunks[yReg] = new SubChunk().rebuild(world, x, y, z); subChunks[yReg].radiation = MathHelper.clamp_float(rad, 0, MAX_RADIATION); world.getChunkFromBlockCoords(x, z).isModified = true; @@ -78,10 +98,79 @@ public class ChunkRadiationHandlerPRISM extends ChunkRadiationHandler { setRadiation(world, x, y, z, getRadiation(world, x, y, z) - rad); } + @Override + public void receiveWorldLoad(WorldEvent.Load event) { + if(!event.world.isRemote) perWorld.put(event.world, new RadPerWorld()); + } + + @Override + public void receiveWorldUnload(WorldEvent.Unload event) { + if(!event.world.isRemote) perWorld.remove(event.world); + } + + @Override + public void receiveChunkLoad(ChunkDataEvent.Load event) { + + if(!event.world.isRemote) { + RadPerWorld radWorld = perWorld.get(event.world); + + if(radWorld != null) { + SubChunk[] chunk = new SubChunk[16]; + + for(int i = 0; i < 16; i++) { + if(!event.getData().getBoolean(NBT_KEY_CHUNK_EXISTS + i)) { + chunk[i] = new SubChunk().rebuild(event.world, event.getChunk().xPosition << 4, i << 4, event.getChunk().zPosition << 4); + continue; + } + SubChunk sub = new SubChunk(); + chunk[i] = sub; + sub.radiation = event.getData().getFloat(NBT_KEY_CHUNK_RADIATION + i); + for(int j = 0; j < 16; j++) sub.xResist[j] = event.getData().getFloat(NBT_KEY_CHUNK_RESISTANCE + "x_" + j + "_" + i); + for(int j = 0; j < 16; j++) sub.yResist[j] = event.getData().getFloat(NBT_KEY_CHUNK_RESISTANCE + "y_" + j + "_" + i); + for(int j = 0; j < 16; j++) sub.zResist[j] = event.getData().getFloat(NBT_KEY_CHUNK_RESISTANCE + "z_" + j + "_" + i); + } + + radWorld.radiation.put(event.getChunk().getChunkCoordIntPair(), chunk); + } + } + } + + @Override + public void receiveChunkSave(ChunkDataEvent.Save event) { + if(!event.world.isRemote) { + RadPerWorld radWorld = perWorld.get(event.world); + if(radWorld != null) { + SubChunk[] chunk = radWorld.radiation.get(event.getChunk().getChunkCoordIntPair()); + for(int i = 0; i < 16; i++) { + SubChunk sub = chunk[i]; + if(sub != null) { + float rad = sub.radiation; + event.getData().setFloat(NBT_KEY_CHUNK_RADIATION + i, rad); + for(int j = 0; j < 16; j++) event.getData().setFloat(NBT_KEY_CHUNK_RESISTANCE + "x_" + j + "_" + i, sub.xResist[j]); + for(int j = 0; j < 16; j++) event.getData().setFloat(NBT_KEY_CHUNK_RESISTANCE + "y_" + j + "_" + i, sub.yResist[j]); + for(int j = 0; j < 16; j++) event.getData().setFloat(NBT_KEY_CHUNK_RESISTANCE + "z_" + j + "_" + i, sub.zResist[j]); + event.getData().setBoolean(NBT_KEY_CHUNK_EXISTS + i, true); + } + } + } + } + } + + @Override + public void receiveChunkUnload(ChunkEvent.Unload event) { + if(!event.world.isRemote) { + RadPerWorld radWorld = perWorld.get(event.world); + if(radWorld != null) { + radWorld.radiation.remove(event.getChunk()); + } + } + } + @Override public void updateSystem() { for(Entry entries : perWorld.entrySet()) { + World world = entries.getKey(); RadPerWorld system = entries.getValue(); //it would be way to expensive to replace the sub-chunks entirely like with the old system @@ -91,15 +180,20 @@ public class ChunkRadiationHandlerPRISM extends ChunkRadiationHandler { sub.radiation = 0; } - for(Entry chunk : system.radiation.entrySet()) { + //has to support additions while iterating + Iterator> it = system.radiation.entrySet().iterator(); + while(it.hasNext()) { + Entry chunk = it.next(); + if(this.getPrevChunkRadiation(chunk.getValue()) <= 0) continue; for(int i = 0; i < 16; i++) { SubChunk sub = chunk.getValue()[i]; if(sub != null) { + if(sub.prevRadiation <= 0 || Float.isNaN(sub.prevRadiation)) continue; float radSpread = 0; - for(ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) radSpread += spreadRadiation(sub, i, chunk.getKey(), system.radiation, dir); - sub.radiation += (sub.prevRadiation - radSpread) * 0.9F; + for(ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) radSpread += spreadRadiation(world, sub, i, chunk.getKey(), chunk.getValue(), system.radiation, dir); + sub.radiation += (sub.prevRadiation - radSpread) * 0.95F; } } } @@ -111,19 +205,45 @@ public class ChunkRadiationHandlerPRISM extends ChunkRadiationHandler { } } - private static float spreadRadiation(SubChunk source, int y, ChunkCoordIntPair origin, HashMap map, ForgeDirection dir) { + /** Returns the amount of radiation spread */ + private static float spreadRadiation(World world, SubChunk source, int y, ChunkCoordIntPair origin, SubChunk[] chunk, HashMap map, ForgeDirection dir) { - //TODO + float spread = 0.1F; + float amount = source.prevRadiation * spread; - return 0F; + if(amount <= 1F) return 0; + + if(dir.offsetY != 0) { + if(dir == Library.POS_Y && y == 15) return amount; // out of world + if(dir == Library.NEG_Y && y == 0) return amount; // out of world + if(chunk[y + dir.offsetY] == null) chunk[y + dir.offsetY] = new SubChunk().rebuild(world, origin.chunkXPos << 4, (y + dir.offsetY) << 4, origin.chunkZPos << 4); + SubChunk to = chunk[y + dir.offsetY]; + return spreadRadiationTo(source, to, amount, dir); + } else { + ChunkCoordIntPair newPos = new ChunkCoordIntPair(origin.chunkXPos + dir.offsetX, origin.chunkZPos + dir.offsetZ); + if(!world.getChunkProvider().chunkExists(newPos.chunkXPos, newPos.chunkZPos)) return amount; + SubChunk[] newChunk = map.get(newPos); + if(newChunk == null) { + newChunk = new SubChunk[16]; + map.put(newPos, newChunk); + } + if(newChunk[y] == null) newChunk[y] = new SubChunk().rebuild(world, newPos.chunkXPos << 4, y << 4, newPos.chunkZPos << 4); + SubChunk to = newChunk[y]; + return spreadRadiationTo(source, to, amount, dir); + } } - public static float getTotalChunkRadiation(SubChunk[] chunk) { - float rad = 0; - for(SubChunk sub : chunk) if(sub != null) rad += sub.radiation; - return rad; + private static float spreadRadiationTo(SubChunk from, SubChunk to, float amount, ForgeDirection movement) { + float resistance = from.getResistanceValue(movement.getOpposite()) + to.getResistanceValue(movement); + resistance /= 1_000F; + float toMove = Math.min(amount / Math.max(resistance, 1F), amount); + to.radiation += toMove; + return toMove; } + //private static float getTotalChunkRadiation(SubChunk[] chunk) { float rad = 0; for(SubChunk sub : chunk) if(sub != null) rad += sub.radiation; return rad; } + private static float getPrevChunkRadiation(SubChunk[] chunk) { float rad = 0; for(SubChunk sub : chunk) if(sub != null) rad += sub.prevRadiation; return rad; } + @Override public void clearSystem(World world) { RadPerWorld system = perWorld.get(world); @@ -171,6 +291,7 @@ public class ChunkRadiationHandlerPRISM extends ChunkRadiationHandler { if(iX == sX || iY == sY || iZ == sZ) { //only redo the three affected slices by this position change Block b = subChunk.getBlockByExtId(iX, iY, iZ); + if(b.getMaterial() == Material.air) continue; float resistance = b.getExplosionResistance(null, world, tX + iX, tY + iY, tZ + iZ, x, y, z); if(iX == sX) xResist[iX] += resistance; if(iY == sY) yResist[iY] += resistance; @@ -204,6 +325,7 @@ public class ChunkRadiationHandlerPRISM extends ChunkRadiationHandler { for(int iZ = 0; iZ < 16; iZ ++) { Block b = subChunk.getBlockByExtId(iX, iY, iZ); + if(b.getMaterial() == Material.air) continue; float resistance = b.getExplosionResistance(null, world, tX + iX, tY + iY, tZ + iZ, x, y, z); xResist[iX] += resistance; yResist[iY] += resistance; diff --git a/src/main/java/com/hbm/handler/radiation/ChunkRadiationManager.java b/src/main/java/com/hbm/handler/radiation/ChunkRadiationManager.java index f1063672a..1c5c8121c 100644 --- a/src/main/java/com/hbm/handler/radiation/ChunkRadiationManager.java +++ b/src/main/java/com/hbm/handler/radiation/ChunkRadiationManager.java @@ -12,7 +12,7 @@ import net.minecraftforge.event.world.WorldEvent; public class ChunkRadiationManager { - public static ChunkRadiationHandler proxy = /*new ChunkRadiationHandlerNT();*/ new ChunkRadiationHandlerSimple(); + public static ChunkRadiationHandler proxy = /*new ChunkRadiationHandlerNT();*/ new ChunkRadiationHandlerSimple(); /*new ChunkRadiationHandlerPRISM();*/ @SubscribeEvent public void onWorldLoad(WorldEvent.Load event) {