From 0427ab89f1753a44b30cbc35ce021cbbdc845109 Mon Sep 17 00:00:00 2001 From: Foghrye4 Date: Thu, 10 Aug 2017 18:52:45 +0300 Subject: fix missing source folder --- .../java/ihl/explosion/ExplosionVectorBlockV2.java | 363 +++++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100644 src/main/java/ihl/explosion/ExplosionVectorBlockV2.java (limited to 'src/main/java/ihl/explosion/ExplosionVectorBlockV2.java') diff --git a/src/main/java/ihl/explosion/ExplosionVectorBlockV2.java b/src/main/java/ihl/explosion/ExplosionVectorBlockV2.java new file mode 100644 index 0000000..e00e19a --- /dev/null +++ b/src/main/java/ihl/explosion/ExplosionVectorBlockV2.java @@ -0,0 +1,363 @@ +package ihl.explosion; + +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.Map.Entry; +import java.util.Random; +import java.util.Set; + +import ihl.IHLMod; +import ihl.utils.IHLUtils; +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; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.world.ExplosionEvent; + +public class ExplosionVectorBlockV2 { + final Set startVectors = new HashSet(); + public final int[][] directionMasks = new int[8][3]; + public final int bits = IHLMod.config.explosionVectorSizeBits; + private final int maxValue = (1 << bits) - 1; + public final int halfValue = (1 << bits - 1) - 1; + private final int maxArraySize = 1 << bits * 3; +// public final int[][] vectors = new int[maxArraySize][2]; + public final int[][] vectors = new int[maxArraySize][0]; + private final Set chunksToUpdate = new HashSet(64); + private final Map cachedDrops = new HashMap(128); + final Map blastWaveByDimensionId = new HashMap(); + private final Map cachedEntities = new HashMap(); + private final Random random = new Random(); + + public ExplosionVectorBlockV2() { + this.precalculateExplosion(); + startVectors.add(0); + 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 }; + } + + public int encodeXYZ(int x, int y, int z) { + return x << bits * 2 | y << bits | z; + } + + public int[] decodeXYZ(int l) { + return new int[] { l >> bits * 2, l >> bits & maxValue, l & maxValue }; + } + + public void precalculateExplosion() { + for (int levelRadius = 1; levelRadius <= this.maxValue; levelRadius++) + for (int ix = 0; ix <= levelRadius; ix++) + for (int iy = 0; iy <= levelRadius; iy++) { + for (int iz = (ix == levelRadius || iy == levelRadius) ? 0 : levelRadius; iz <= levelRadius; iz++) { + int vxyz = encodeXYZ(ix, iy, iz); + int[] prevXYZ = new int[] { ix, iy, iz }; + reduceCoordinate(prevXYZ, levelRadius); + int pvxyz = encodeXYZ(prevXYZ[0], prevXYZ[1], prevXYZ[2]); + findFreeSpace(pvxyz, vxyz); + } + } + } + + private void findFreeSpace(int pvxyz, int vxyz) { + int[] nV = new int[vectors[pvxyz].length+1]; + for(int i=0;i=pxyz[0] && y>=pxyz[1] && z>=pxyz[2]){ + x-=rx; + y-=ry; + z-=rz; + } + pxyz[0]=x<0?0:(int)x; + pxyz[1]=y<0?0:(int)y; + pxyz[2]=z<0?0:(int)z; + } + + public void breakBlocksAndGetDescendants(World world, int sourceX, int sourceY, int sourceZ, Explosion explosion, + int ev, int power, int[] directionMask) { + power = this.getNewPowerAndProcessBlocks(world, ev, sourceX, sourceY, sourceZ, explosion, power, directionMask); + power = (int) (power * 0.94) - 1; + if (power > 1) { + if (this.vectors[ev].length==0) { + int[] xyz = decodeXYZ(ev); + int xb = xyz[0] >> bits - 1; + int yb = xyz[1] >> bits - 1; + int zb = xyz[2] >> bits - 1; + int hashb = xb << 2 | yb << 1 | zb; + xyz[0] -= xb * halfValue; + xyz[1] -= yb * halfValue; + xyz[2] -= zb * halfValue; + if (hashb == 0 || xb > 1 || yb > 1 || zb > 1) { + throw new ArithmeticException("End vectors shall be higher than half value"); + } + int ev2 = encodeXYZ(xyz[0], xyz[1], xyz[2]); + breakBlocksAndGetDescendants(world, sourceX + xb * halfValue * directionMask[0], + sourceY + yb * halfValue * directionMask[1], sourceZ + zb * halfValue * directionMask[2], + explosion, ev2, power, directionMask); + } else { + for (int d1 : this.vectors[ev]) { + breakBlocksAndGetDescendants(world, sourceX, sourceY, sourceZ, explosion, d1, power, + directionMask); + } + } + } + } + + 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 remainingPower = this.tryDestroyBlock(world, absX, absY, absZ, sourceX, sourceY, sourceZ, power1, + explosion); + return remainingPower; + } 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 tryDestroyBlock(World world, int absX, int absY, int absZ, int sourceX, int sourceY, int sourceZ, + int power, Explosion explosion) { + Chunk chunk = world.getChunkProvider().provideChunk(absX >> 4, absZ >> 4); + ExtendedBlockStorage ebs = this.getEBS(chunk, absX, absY, absZ); + if (ebs == null) { + return power; + } else { + Block block = ebs.getBlockByExtId(absX & 15, absY & 15, absZ & 15); + if (block.getBlockHardness(world, absX, absY, absZ) < 0) { + return 0; + } else if (absX == sourceX && absY == sourceY && absZ == sourceZ) { + 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); + } + return power; + } else { + int remainingPower = power + - (int) (block.getExplosionResistance(null, world, absX, absY, absZ, sourceX, sourceY, sourceZ) + * 10f + 0.5f); + if (remainingPower >= 0) { + 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); + } + List dropsList = block.getDrops(world, absX, absY, absZ, + ebs.getExtBlockMetadata(absX & 15, absY & 15, absZ & 15), 0); + Iterator drops = dropsList.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[] entities = this.getFromOrCreateCache(world, ebs, absX, absY, absZ); + if (entities != null && entities[array_index] != null) { + entities[array_index].attackEntityFrom(DamageSource.setExplosionSource(explosion), power / 10f); + } + } else { + block.onNeighborBlockChange(world, absX, absY, absZ, block); + if (random.nextInt(8) == 0) { + if ((++absY & 15) != 0) { + 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)) { + this.placeDrops(world, absX, absY, absZ); + } + } + } + } + return remainingPower; + } + } + } + + public Entity[] getFromOrCreateCache(World world, ExtendedBlockStorage ebs, int absX, int absY, int absZ) { + Entity[] entities = this.cachedEntities.get(ebs); + if (entities == null) { + Chunk chunk = world.getChunkProvider().provideChunk(absX >> 4, absZ >> 4); + List eList = this.getEntityList(chunk, absX, absY, absZ); + if (eList != null && !eList.isEmpty()) { + entities = new Entity[4096]; + Iterator eListI = eList.iterator(); + this.cachedEntities.put(ebs, entities); + 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 & 15; + int ry = entityY & 15; + int rz = entityZ & 15; + int array_index = ry << 8 | rz << 4 | rx; + entities[array_index] = entity; + } + } + } + return entities; + } + + 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]; + } + + private void placeDrops(World world, int x, int y, int z) { + Iterator> di = this.cachedDrops.entrySet().iterator(); + if (di.hasNext()) { + Entry cde = di.next(); + while (di.hasNext()) { + cde = di.next(); + } + 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(); + } 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) { + Iterator ci = this.chunksToUpdate.iterator(); + while (ci.hasNext()) { + Chunk chunk = ci.next(); + chunk.generateSkylightMap(); + Arrays.fill(chunk.updateSkylightColumns, true); + chunk.func_150804_b(false); + } + 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)); + } + } + this.chunksToUpdate.clear(); + } + + public void doExplosion(World world, int sourceX, int sourceY, int sourceZ, final Set startVectors1, + int startPower, int[] directionMask, Explosion explosion) { + for (int sv : startVectors1) { + this.breakBlocksAndGetDescendants(world, sourceX - (directionMask[0] < 0 ? 1 : 0), + sourceY - (directionMask[1] < 0 ? 1 : 0), sourceZ - (directionMask[2] < 0 ? 1 : 0), explosion, sv, + startPower, directionMask); + } + // Free and clean resources + this.cachedEntities.clear(); + } + + public void doExplosion(World world, int sourceX, int sourceY, int sourceZ, final Set startVectors1, + int startPower) { + IHLMod.log.info("Starting explosion server"); + Explosion explosion = new Explosion(world, null, sourceX, sourceY, sourceZ, 100f); + if (!MinecraftForge.EVENT_BUS.post(new ExplosionEvent.Start(world, explosion))) { + for (int[] directionMask : directionMasks) { + this.doExplosion(world, sourceX, sourceY, sourceZ, startVectors1, startPower, directionMask, explosion); + } + sendChunkUpdateToPlayersInExplosionAffectedZone(world, sourceX, sourceY, sourceZ); + for (Entry entry : this.cachedDrops.entrySet()) { + IHLEntityFallingPile fallingPile = new IHLEntityFallingPile(world); + fallingPile.setPosition(sourceX + 0.5d, sourceY + 0.5d, sourceZ + 0.5d); + fallingPile.setEntityItemStack(entry.getValue()); + fallingPile.setVelocity(random.nextDouble() - 0.5d, random.nextDouble() * 2, + random.nextDouble() - 0.5d); + world.spawnEntityInWorld(fallingPile); + } + this.cachedDrops.clear(); + } + } +} \ No newline at end of file -- cgit v1.2.3