Applied-Energistics-2-tiler.../src/main/java/appeng/spatial/CachedPlane.java
LordMZTE f67fb6a129
Some checks failed
continuous-integration/drone/push Build is failing
chore: format code
2022-12-02 17:40:47 +01:00

476 lines
17 KiB
Java

/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.spatial;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import appeng.api.AEApi;
import appeng.api.definitions.IBlockDefinition;
import appeng.api.movable.IMovableHandler;
import appeng.api.movable.IMovableRegistry;
import appeng.api.util.WorldCoord;
import appeng.core.AELog;
import appeng.core.worlddata.WorldData;
import appeng.util.Platform;
import net.minecraft.block.Block;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.ChunkPosition;
import net.minecraft.world.NextTickListEntry;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import net.minecraftforge.common.util.ForgeDirection;
public class CachedPlane {
private final int x_size;
private final int z_size;
private final int cx_size;
private final int cz_size;
private final int x_offset;
private final int y_offset;
private final int z_offset;
private final int y_size;
private final Chunk[][] myChunks;
private final Column[][] myColumns;
private final LinkedList<TileEntity> tiles = new LinkedList<TileEntity>();
private final LinkedList<NextTickListEntry> ticks
= new LinkedList<NextTickListEntry>();
private final World world;
private final IMovableRegistry reg = AEApi.instance().registries().movable();
private final LinkedList<WorldCoord> updates = new LinkedList<WorldCoord>();
private final IBlockDefinition matrixFrame
= AEApi.instance().definitions().blocks().matrixFrame();
private int verticalBits;
public CachedPlane(
final World w,
final int minX,
final int minY,
final int minZ,
final int maxX,
final int maxY,
final int maxZ
) {
this.world = w;
this.x_size = maxX - minX + 1;
this.y_size = maxY - minY + 1;
this.z_size = maxZ - minZ + 1;
this.x_offset = minX;
this.y_offset = minY;
this.z_offset = minZ;
final int minCX = minX >> 4;
final int minCY = minY >> 4;
final int minCZ = minZ >> 4;
final int maxCX = maxX >> 4;
final int maxCY = maxY >> 4;
final int maxCZ = maxZ >> 4;
this.cx_size = maxCX - minCX + 1;
final int cy_size = maxCY - minCY + 1;
this.cz_size = maxCZ - minCZ + 1;
this.myChunks = new Chunk[this.cx_size][this.cz_size];
this.myColumns = new Column[this.x_size][this.z_size];
this.verticalBits = 0;
for (int cy = 0; cy < cy_size; cy++) {
this.verticalBits |= 1 << (minCY + cy);
}
for (int x = 0; x < this.x_size; x++) {
for (int z = 0; z < this.z_size; z++) {
this.myColumns[x][z] = new Column(
w.getChunkFromChunkCoords((minX + x) >> 4, (minZ + z) >> 4),
(minX + x) & 0xF,
(minZ + z) & 0xF,
minCY,
cy_size
);
}
}
final IMovableRegistry mr = AEApi.instance().registries().movable();
for (int cx = 0; cx < this.cx_size; cx++) {
for (int cz = 0; cz < this.cz_size; cz++) {
final LinkedList<Entry<ChunkPosition, TileEntity>> rawTiles
= new LinkedList<Entry<ChunkPosition, TileEntity>>();
final LinkedList<ChunkPosition> deadTiles
= new LinkedList<ChunkPosition>();
final Chunk c = w.getChunkFromChunkCoords(minCX + cx, minCZ + cz);
this.myChunks[cx][cz] = c;
rawTiles.addAll(
((HashMap<ChunkPosition, TileEntity>) c.chunkTileEntityMap).entrySet()
);
for (final Entry<ChunkPosition, TileEntity> tx : rawTiles) {
final ChunkPosition cp = tx.getKey();
final TileEntity te = tx.getValue();
if (te.xCoord >= minX && te.xCoord <= maxX && te.yCoord >= minY
&& te.yCoord <= maxY && te.zCoord >= minZ && te.zCoord <= maxZ) {
if (mr.askToMove(te)) {
this.tiles.add(te);
deadTiles.add(cp);
} else {
final Object[] details
= this.myColumns[te.xCoord - minX][te.zCoord - minZ]
.getDetails(te.yCoord);
final Block blk = (Block) details[0];
// don't skip air, just let the code replace it...
if (blk != null
&& blk.isAir(c.worldObj, te.xCoord, te.yCoord, te.zCoord)
&& blk.isReplaceable(
c.worldObj, te.xCoord, te.yCoord, te.zCoord
)) {
c.worldObj.setBlock(
te.xCoord, te.yCoord, te.zCoord, Platform.AIR_BLOCK
);
c.worldObj.notifyBlocksOfNeighborChange(
te.xCoord, te.yCoord, te.zCoord, Platform.AIR_BLOCK
);
} else {
this.myColumns[te.xCoord - minX][te.zCoord - minZ]
.setSkip(te.yCoord);
}
}
}
}
for (final ChunkPosition cp : deadTiles) {
c.chunkTileEntityMap.remove(cp);
}
final long k = this.getWorld().getTotalWorldTime();
final List list = this.getWorld().getPendingBlockUpdates(c, false);
if (list != null) {
for (final Object o : list) {
final NextTickListEntry entry = (NextTickListEntry) o;
if (entry.xCoord >= minX && entry.xCoord <= maxX
&& entry.yCoord >= minY && entry.yCoord <= maxY
&& entry.zCoord >= minZ && entry.zCoord <= maxZ) {
final NextTickListEntry newEntry = new NextTickListEntry(
entry.xCoord,
entry.yCoord,
entry.zCoord,
entry.func_151351_a()
);
newEntry.scheduledTime = entry.scheduledTime - k;
this.ticks.add(newEntry);
}
}
}
}
}
for (final TileEntity te : this.tiles) {
try {
this.getWorld().loadedTileEntityList.remove(te);
} catch (final Exception e) {
AELog.debug(e);
}
}
}
private IMovableHandler getHandler(final TileEntity te) {
final IMovableRegistry mr = AEApi.instance().registries().movable();
return mr.getHandler(te);
}
void swap(final CachedPlane dst) {
final IMovableRegistry mr = AEApi.instance().registries().movable();
if (dst.x_size == this.x_size && dst.y_size == this.y_size
&& dst.z_size == this.z_size) {
AELog.info(
"Block Copy Scale: " + this.x_size + ", " + this.y_size + ", "
+ this.z_size
);
long startTime = System.nanoTime();
for (int x = 0; x < this.x_size; x++) {
for (int z = 0; z < this.z_size; z++) {
final Column a = this.myColumns[x][z];
final Column b = dst.myColumns[x][z];
for (int y = 0; y < this.y_size; y++) {
final int src_y = y + this.y_offset;
final int dst_y = y + dst.y_offset;
if (a.doNotSkip(src_y) && b.doNotSkip(dst_y)) {
final Object[] aD = a.getDetails(src_y);
final Object[] bD = b.getDetails(dst_y);
a.setBlockIDWithMetadata(src_y, bD);
b.setBlockIDWithMetadata(dst_y, aD);
} else {
this.markForUpdate(
x + this.x_offset, src_y, z + this.z_offset
);
dst.markForUpdate(x + dst.x_offset, dst_y, z + dst.z_offset);
}
}
}
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
AELog.info("Block Copy Time: " + duration);
for (final TileEntity te : this.tiles) {
dst.addTile(
te.xCoord - this.x_offset,
te.yCoord - this.y_offset,
te.zCoord - this.z_offset,
te,
this,
mr
);
}
for (final TileEntity te : dst.tiles) {
this.addTile(
te.xCoord - dst.x_offset,
te.yCoord - dst.y_offset,
te.zCoord - dst.z_offset,
te,
dst,
mr
);
}
for (final NextTickListEntry entry : this.ticks) {
dst.addTick(
entry.xCoord - this.x_offset,
entry.yCoord - this.y_offset,
entry.zCoord - this.z_offset,
entry
);
}
for (final NextTickListEntry entry : dst.ticks) {
this.addTick(
entry.xCoord - dst.x_offset,
entry.yCoord - dst.y_offset,
entry.zCoord - dst.z_offset,
entry
);
}
startTime = System.nanoTime();
this.updateChunks();
dst.updateChunks();
endTime = System.nanoTime();
duration = endTime - startTime;
AELog.info("Update Time: " + duration);
}
}
private void markForUpdate(final int x, final int y, final int z) {
this.getUpdates().add(new WorldCoord(x, y, z));
for (final ForgeDirection d : ForgeDirection.VALID_DIRECTIONS) {
this.getUpdates().add(
new WorldCoord(x + d.offsetX, y + d.offsetY, z + d.offsetZ)
);
}
}
private void
addTick(final int x, final int y, final int z, final NextTickListEntry entry) {
this.getWorld().scheduleBlockUpdate(
x + this.x_offset,
y + this.y_offset,
z + this.z_offset,
entry.func_151351_a(),
(int) entry.scheduledTime
);
}
private void addTile(
final int x,
final int y,
final int z,
final TileEntity te,
final CachedPlane alternateDestination,
final IMovableRegistry mr
) {
try {
final Column c = this.myColumns[x][z];
if (c.doNotSkip(y + this.y_offset) || alternateDestination == null) {
final IMovableHandler handler = this.getHandler(te);
try {
handler.moveTile(
te,
this.getWorld(),
x + this.x_offset,
y + this.y_offset,
z + this.z_offset
);
} catch (final Throwable e) {
AELog.debug(e);
// attempt recovery...
te.setWorldObj(this.getWorld());
te.xCoord = x;
te.yCoord = y;
te.zCoord = z;
c.c.func_150812_a(c.x, y + y, c.z, te);
// c.c.setChunkTileEntity( c.x, y + y, c.z, te );
if (c.c.isChunkLoaded) {
this.getWorld().addTileEntity(te);
this.getWorld().markBlockForUpdate(x, y, z);
}
}
mr.doneMoving(te);
} else {
alternateDestination.addTile(x, y, z, te, null, mr);
}
} catch (final Throwable e) {
AELog.debug(e);
}
}
private void updateChunks() {
// update shit..
for (int x = 0; x < this.cx_size; x++) {
for (int z = 0; z < this.cz_size; z++) {
final Chunk c = this.myChunks[x][z];
c.resetRelightChecks();
c.generateSkylightMap();
c.isModified = true;
}
}
// send shit...
for (int x = 0; x < this.cx_size; x++) {
for (int z = 0; z < this.cz_size; z++) {
final Chunk c = this.myChunks[x][z];
for (int y = 1; y < 255; y += 32) {
WorldData.instance().compassData().service().updateArea(
this.getWorld(), c.xPosition << 4, y, c.zPosition << 4
);
}
Platform.sendChunk(c, this.verticalBits);
}
}
}
LinkedList<WorldCoord> getUpdates() {
return this.updates;
}
World getWorld() {
return this.world;
}
private class Column {
private final int x;
private final int z;
private final Chunk c;
private final Object[] ch = { 0, 0, 0 };
private final ExtendedBlockStorage[] storage;
private List<Integer> skipThese = null;
public Column(
final Chunk chunk,
final int x,
final int z,
final int chunkY,
final int chunkHeight
) {
this.x = x;
this.z = z;
this.c = chunk;
this.storage = this.c.getBlockStorageArray();
// make sure storage exists before hand...
for (int ay = 0; ay < chunkHeight; ay++) {
final int by = (ay + chunkY);
ExtendedBlockStorage extendedblockstorage = this.storage[by];
if (extendedblockstorage == null) {
extendedblockstorage = this.storage[by] = new ExtendedBlockStorage(
by << 4, !this.c.worldObj.provider.hasNoSky
);
}
}
}
private void setBlockIDWithMetadata(final int y, final Object[] blk) {
for (final Block matrixFrameBlock :
CachedPlane.this.matrixFrame.maybeBlock().asSet()) {
if (blk[0] == matrixFrameBlock) {
blk[0] = Platform.AIR_BLOCK;
}
}
final ExtendedBlockStorage extendedBlockStorage = this.storage[y >> 4];
extendedBlockStorage.func_150818_a(this.x, y & 15, this.z, (Block) blk[0]);
// extendedBlockStorage.setExtBlockID( x, y & 15, z, blk[0] );
extendedBlockStorage.setExtBlockMetadata(
this.x, y & 15, this.z, (Integer) blk[1]
);
extendedBlockStorage.setExtBlocklightValue(
this.x, y & 15, this.z, (Integer) blk[2]
);
}
private Object[] getDetails(final int y) {
final ExtendedBlockStorage extendedblockstorage = this.storage[y >> 4];
this.ch[0] = extendedblockstorage.getBlockByExtId(this.x, y & 15, this.z);
this.ch[1] = extendedblockstorage.getExtBlockMetadata(this.x, y & 15, this.z);
this.ch[2]
= extendedblockstorage.getExtBlocklightValue(this.x, y & 15, this.z);
return this.ch;
}
private boolean doNotSkip(final int y) {
final ExtendedBlockStorage extendedblockstorage = this.storage[y >> 4];
if (CachedPlane.this.reg.isBlacklisted(
extendedblockstorage.getBlockByExtId(this.x, y & 15, this.z)
)) {
return false;
}
return this.skipThese == null || !this.skipThese.contains(y);
}
private void setSkip(final int yCoord) {
if (this.skipThese == null) {
this.skipThese = new LinkedList<Integer>();
}
this.skipThese.add(yCoord);
}
}
}