package ihl.explosion; import ihl.IHLMod; import ihl.utils.IHLUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import net.minecraft.block.Block; import net.minecraft.entity.Entity; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.network.play.server.S26PacketMapChunkBulk; import net.minecraft.util.DamageSource; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.Explosion; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; public class ExplosionVectorBlockV2 { public int[] startVectors = new int[1]; private final int[][] directionMasks = new int[8][3]; private final int bits = 8; private final int maxValue = (1<> cachedBlockDrops = new HashMap>(128); public final List dropBlocksPos = new ArrayList(64); public Set chunksToUpdate=new HashSet(64); public Map cachedDrops = new HashMap(128); public Set dropBlocks = new HashSet(); public Map blastWaveByDimensionId = new HashMap(); private Entity[] cachedEntities = new Entity[maxArraySize]; public ExplosionVectorBlockV2() { this.precalculateExplosion(); directionMasks[0] = new int[] {1,1,1}; directionMasks[1] = new int[] {-1,1,1}; directionMasks[2] = new int[] {1,-1,1}; directionMasks[3] = new int[] {1,1,-1}; directionMasks[4] = new int[] {-1,-1,1}; directionMasks[5] = new int[] {1,-1,-1}; directionMasks[6] = new int[] {-1,1,-1}; directionMasks[7] = new int[] {-1,-1,-1}; Arrays.fill(cachedBlockHardness,-1); } private int encodeXYZ(int x, int y, int z) { return x<>bits*2,l>>bits&maxValue,l&maxValue}; } public void precalculateExplosion() { startVectors[0]=0; explosionPowerDampingFactor[0]=1f; for(int levelRadius=1; levelRadiusMath.round(levelRadius*1.8f)) { pxyz[0]=IHLUtils.reduceVariableByAbsoluteValue(pxyz[0]); pxyz[1]=IHLUtils.reduceVariableByAbsoluteValue(pxyz[1]); pxyz[2]=IHLUtils.reduceVariableByAbsoluteValue(pxyz[2]); } else if(Math.abs(pxyz[0])<=Math.abs(pxyz[1]) && Math.abs(pxyz[0])<=Math.abs(pxyz[2])) { pxyz[1]=IHLUtils.reduceVariableByAbsoluteValue(pxyz[1]); pxyz[2]=IHLUtils.reduceVariableByAbsoluteValue(pxyz[2]); } else if(Math.abs(pxyz[1])<=Math.abs(pxyz[0]) && Math.abs(pxyz[1])<=Math.abs(pxyz[2])) { pxyz[0]=IHLUtils.reduceVariableByAbsoluteValue(pxyz[0]); pxyz[2]=IHLUtils.reduceVariableByAbsoluteValue(pxyz[2]); } else if(Math.abs(pxyz[2])<=Math.abs(pxyz[0]) && Math.abs(pxyz[2])<=Math.abs(pxyz[1])) { pxyz[1]=IHLUtils.reduceVariableByAbsoluteValue(pxyz[1]); pxyz[0]=IHLUtils.reduceVariableByAbsoluteValue(pxyz[0]); } } public void setPower(int[] sv2, int power1) { for(int ev:sv2) { this.setPower(ev, power1); } } public void setPower(int ev, int power1) { this.explosionPower[ev]=power1; } public int[] breakBlocksAndGetDescendants(World world, int sourceX,int sourceY,int sourceZ, Explosion explosion, int ev, int[] directionMask) { int power1 = explosionPower[ev]; power1 = this.getNewPowerAndProcessBlocks(world, ev, sourceX, sourceY, sourceZ, explosion, power1, directionMask); power1 = (int)(power1*explosionPowerDampingFactor[ev])-1; if(power1<=1 || this.vectors[ev][0]==0) { return null; } else { for(int d1:this.vectors[ev]) { if(d1!=0) { explosionPower[d1]=power1; } } return this.vectors[ev]; } } private int getNewPowerAndProcessBlocks(World world, int ev, int sourceX, int sourceY, int sourceZ, Explosion explosion, int power2, int[] directionMask) { int power1=power2; int[] xyz = decodeXYZ(ev); int absX = xyz[0]*directionMask[0] + sourceX; int absY = xyz[1]*directionMask[1] + sourceY; int absZ = xyz[2]*directionMask[2] + sourceZ; if(absY<0 || absY>=256) { return 0; } int absEBSX = absX>>4; int absEBSZ = absZ>>4; if(world.getChunkProvider().chunkExists(absEBSX, absEBSZ)) { if(world.getChunkProvider().provideChunk(absEBSX, absEBSZ).getTopFilledSegment()+24>=absY) { int explosionResistance = this.getBlockResistance(world, ev, absX, absY, absZ, sourceX, sourceY, sourceZ, explosion, directionMask); if(explosionResistance>=power1) { if(this.cachedFluidBlocks[ev]!=0) { //IHLMod.log.info("Schleduling update for "+Block.getBlockById(this.cachedFluidBlocks[ev]).getUnlocalizedName()); Block block = Block.getBlockById(this.cachedFluidBlocks[ev]); block.onNeighborBlockChange(world, absX, absY, absZ, block); } else { this.dropBlocksPos.add(new int[] {absX, absY+1, absZ}); } return 0; } else { power1-=explosionResistance; this.onBlockDestroy(world, ev, absX, absY, absZ, power1, explosion); return power1; } } else { return 0; } } else { WorldSavedDataBlastWave blastWave = null; int dimensionId = world.provider.dimensionId; if(this.blastWaveByDimensionId.containsKey(dimensionId)) { blastWave=this.blastWaveByDimensionId.get(dimensionId); } else { blastWave=new WorldSavedDataBlastWave("blastWave"); this.blastWaveByDimensionId.put(dimensionId, blastWave); } long chunkXZKey = ChunkCoordIntPair.chunkXZ2Int(absEBSX, absEBSZ); blastWave.scheduleExplosionEffectsOnChunkLoad(chunkXZKey, ev, sourceX, sourceY, sourceZ, power1, directionMask); return 0; } } public int getBlockResistance(World world, int ev, int absX, int absY, int absZ, int sourceX, int sourceY, int sourceZ, Explosion explosion, int[] directionMask) { if(this.cachedBlockHardness[ev]!=-1) { return this.cachedBlockHardness[ev]; } else { this.precacheEBSBlocks(world, absX, absY, absZ, sourceX, sourceY, sourceZ, explosion, directionMask); return this.cachedBlockHardness[ev]; } } public void precacheEBSBlocks(World world, int absX, int absY, int absZ, int sourceX, int sourceY, int sourceZ, Explosion explosion, int[] directonMask) { Chunk chunk = world.getChunkProvider().provideChunk(absX>>4, absZ>>4); List eList = this.getEntityList(chunk, absX, absY, absZ); if(eList!=null) { Iterator eListI = eList.iterator(); while(eListI.hasNext()) { Entity entity = eListI.next(); int entityX = (int)entity.boundingBox.minX; int entityY = (int)entity.boundingBox.minY; int entityZ = (int)entity.boundingBox.minZ; int rx = (entityX - sourceX) * directonMask[0]; int ry = (entityY - sourceY) * directonMask[1]; int rz = (entityZ - sourceZ) * directonMask[2]; int ev = this.encodeXYZ(rx, ry, rz); if(rx >= 0 && ry >= 0 && rz >= 0 && ev>=0 && ev>8) & 15)|(absY & 0xFFFFFFF0); int blockWorldZ = ((i4>>4) & 15)|(absZ & 0xFFFFFFF0); int rx = (blockWorldX - sourceX) * directonMask[0]; int ry = (blockWorldY - sourceY) * directonMask[1]; int rz = (blockWorldZ - sourceZ) * directonMask[2]; int ev = this.encodeXYZ(rx, ry, rz); if(rx >= 0 && ry >= 0 && rz >= 0 && ev>=0 && ev>8) & 15, (i4>>4) & 15) << 8; } int blockWorldX = (i4 & 15)|(absX & 0xFFFFFFF0); int blockWorldY = ((i4>>8) & 15)|(absY & 0xFFFFFFF0); int blockWorldZ = ((i4>>4) & 15)|(absZ & 0xFFFFFFF0); int rx = (blockWorldX - sourceX) * directonMask[0]; int ry = (blockWorldY - sourceY) * directonMask[1]; int rz = (blockWorldZ - sourceZ) * directonMask[2]; int ev = this.encodeXYZ(rx, ry, rz); if(rx >= 0 && ry >= 0 && rz >= 0 && ev>=0 && ev dropsList = (block.getDrops(world, blockWorldX, blockWorldY, blockWorldZ, ebs.getExtBlockMetadata(i4 & 15, (i4>>8) & 15, (i4>>4) & 15), 0)); if(dropsList!=null) { this.cachedBlockDrops.put(ev, dropsList); } } if(block.getBlockHardness(world, blockWorldX, blockWorldY, blockWorldZ)<0) { this.cachedBlockHardness[ev]=Integer.MAX_VALUE; } else if(ev==0 && directonMask[0]+directonMask[1]+directonMask[2]==3) { this.cachedBlockHardness[ev]=0; } else { int br=Math.round(block.getExplosionResistance(null, world, blockWorldX, blockWorldY, blockWorldZ, sourceX, sourceY, sourceZ)*10f); this.cachedBlockHardness[ev]=br; } if(block.getMaterial().isLiquid()) { this.cachedFluidBlocks[ev]=var4; } } } } } public ExtendedBlockStorage getEBS(Chunk chunk, int absX, int absY, int absZ) { ExtendedBlockStorage[] ebsA = chunk.getBlockStorageArray(); ExtendedBlockStorage ebs = ebsA[absY>>4]; if(ebs!=null) { this.chunksToUpdate.add(chunk); } return ebs; } @SuppressWarnings("unchecked") public List getEntityList(Chunk chunk, int absX, int absY, int absZ) { return chunk.entityLists[absY>>4]; } public void onBlockDestroy(World world, int ev, int absX,int absY,int absZ, int power, Explosion explosion) { Chunk chunk = world.getChunkProvider().provideChunk(absX>>4, absZ>>4); ExtendedBlockStorage ebs = this.getEBS(chunk, absX, absY, absZ); if(ebs==null || ebs.isEmpty()) { return; } int array_index = (absY & 15)<<8 | (absZ & 15)<<4 | (absX & 15); if(ebs.getBlockLSBArray()[array_index] != 0 && ebs.getBlockMSBArray()!=null && ebs.getBlockMSBArray().get(absX & 15, absY & 15, absZ & 15) != 0) { ebs.blockRefCount--; } ebs.getBlockLSBArray()[array_index] = 0; if(ebs.getBlockMSBArray()!=null){ ebs.getBlockMSBArray().set(absX & 15, absY & 15, absZ & 15, 0); } if(this.cachedBlockDrops.containsKey(ev)) { Iterator drops = this.cachedBlockDrops.remove(ev).iterator(); while(drops.hasNext()) { ItemStack drop = drops.next(); int key = Item.getIdFromItem(drop.getItem())^(drop.getItemDamage()<<16); if(this.cachedDrops.containsKey(key)) { this.cachedDrops.get(key).stackSize+=drop.stackSize; } else { this.cachedDrops.put(key, drop); } } } Entity victim = this.cachedEntities[ev]; if(victim!=null) { victim.attackEntityFrom(DamageSource.setExplosionSource(explosion), power/10f); this.cachedEntities[ev]=null; } this.dropBlocks.add(ev); } private void addDrops(World world, int sourceX, int sourceY, int sourceZ, int[] directionMask) { Iterator> di = this.cachedDrops.entrySet().iterator(); Entry cde = di.next(); while(di.hasNext() && this.dropBlocksPos.size() > 0) { int[] xyz = this.dropBlocksPos.remove(this.dropBlocksPos.size()-1); int x = xyz[0]; int y = xyz[1]; int z = xyz[2]; int rx = (x - sourceX) * directionMask[0]; int ry = (y - sourceY) * directionMask[1]; int rz = (z - sourceZ) * directionMask[2]; int ev = encodeXYZ(rx,ry,rz); int ev2 = encodeXYZ(rx,ry-1,rz); if(this.dropBlocks.contains(ev) && !this.dropBlocks.contains(ev2)) { ItemStack stack = cde.getValue(); if(stack!=null && stack.getItem()!=null && stack.stackSize>0) { if(stack.stackSize <= stack.getMaxStackSize()) { if(stack.stackSize>0) { PileTileEntity pte = new PileTileEntity(); pte.xCoord=x; pte.yCoord=y; pte.zCoord=z; pte.setWorldObj(world); pte.validate(); pte.setContent(stack); IHLUtils.setBlockAndTileEntityRaw(world, x, y, z, PileBlock.instance, pte); } di.remove(); if(di.hasNext()) { cde = di.next(); } else { return; } } else { ItemStack stack1=stack.copy(); stack1.stackSize=stack.getMaxStackSize(); PileTileEntity pte = new PileTileEntity(); pte.content=stack1; IHLUtils.setBlockAndTileEntityRaw(world, x, y, z, PileBlock.instance, pte); stack.stackSize-=stack.getMaxStackSize(); } } } } } public void sendChunkUpdateToPlayersInExplosionAffectedZone(World world, int sourceX, int sourceY, int sourceZ) { // Set clientSideChunkXZKeySet = new HashSet(); Iterator ci = this.chunksToUpdate.iterator(); while(ci.hasNext()) { Chunk chunk = ci.next(); chunk.generateSkylightMap(); Arrays.fill(chunk.updateSkylightColumns, true); chunk.func_150804_b(false); // long chunkXZKey = ChunkCoordIntPair.chunkXZ2Int(chunk.xPosition, chunk.zPosition); // clientSideChunkXZKeySet.add(chunkXZKey); } List chunks = new ArrayList(); chunks.addAll(this.chunksToUpdate); for(Object player:world.playerEntities) { if(player instanceof EntityPlayerMP) { EntityPlayerMP playerMP = (EntityPlayerMP)player; playerMP.playerNetServerHandler.sendPacket(new S26PacketMapChunkBulk(chunks)); } } // IHLMod.proxy.sendChunksLightUpdateQuery(world, sourceX, sourceY, sourceZ, clientSideChunkXZKeySet); this.chunksToUpdate.clear(); } public void doExplosion(World world, int sourceX, int sourceY, int sourceZ, final int[] startVectors1, int[] directionMask, Explosion explosion) { boolean doExplosion=true; int[] sv = null; int svsize = 0; while(doExplosion) { int[] sv2= new int[1<