use of forestry.api.multiblock.IMultiblockComponent in project ForestryMC by ForestryMC.
the class MultiblockControllerBase method auditParts.
@Override
public void auditParts() {
HashSet<IMultiblockComponent> deadParts = new HashSet<>();
for (IMultiblockComponent part : connectedParts) {
BlockPos partCoord = part.getCoordinates();
if (isInvalid(part) || TileUtil.getTile(world, partCoord) != part) {
onDetachBlock(part);
deadParts.add(part);
}
}
connectedParts.removeAll(deadParts);
Log.warning("[%s] Controller found %d dead parts during an audit, %d parts remain attached", world.isRemote ? "CLIENT" : "SERVER", deadParts.size(), connectedParts.size());
}
use of forestry.api.multiblock.IMultiblockComponent in project ForestryMC by ForestryMC.
the class MultiblockControllerBase method recalculateMinMaxCoords.
@Override
public void recalculateMinMaxCoords() {
minimumCoord = new BlockPos(Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE);
maximumCoord = new BlockPos(Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE);
for (IMultiblockComponent part : connectedParts) {
BlockPos partCoords = part.getCoordinates();
int minX = minimumCoord.getX();
int minY = minimumCoord.getY();
int minZ = minimumCoord.getZ();
int maxX = maximumCoord.getX();
int maxY = maximumCoord.getY();
int maxZ = maximumCoord.getZ();
if (partCoords.getX() < minimumCoord.getX()) {
minX = partCoords.getX();
}
if (partCoords.getX() > maximumCoord.getX()) {
maxX = partCoords.getX();
}
if (partCoords.getY() < minimumCoord.getY()) {
minY = partCoords.getY();
}
if (partCoords.getY() > maximumCoord.getY()) {
maxY = partCoords.getY();
}
if (partCoords.getZ() < minimumCoord.getZ()) {
minZ = partCoords.getZ();
}
if (partCoords.getZ() > maximumCoord.getZ()) {
maxZ = partCoords.getZ();
}
minimumCoord = new BlockPos(minX, minY, minZ);
maximumCoord = new BlockPos(maxX, maxY, maxZ);
}
}
use of forestry.api.multiblock.IMultiblockComponent in project ForestryMC by ForestryMC.
the class MultiblockControllerBase method checkForDisconnections.
@Override
public Set<IMultiblockComponent> checkForDisconnections() {
if (!this.shouldCheckForDisconnections) {
return Collections.emptySet();
}
if (this.isEmpty()) {
MultiblockRegistry.addDeadController(world, this);
return Collections.emptySet();
}
IChunkProvider chunkProvider = world.getChunkProvider();
// Invalidate our reference coord, we'll recalculate it shortly
referenceCoord = null;
// Reset visitations and find the minimum coordinate
Set<IMultiblockComponent> deadParts = new HashSet<>();
BlockPos c;
IMultiblockComponent referencePart = null;
int originalSize = connectedParts.size();
for (IMultiblockComponent part : connectedParts) {
// This happens during chunk unload.
BlockPos partCoord = part.getCoordinates();
if (chunkProvider.getLoadedChunk(partCoord.getX() >> 4, partCoord.getZ() >> 4) == null || isInvalid(part)) {
deadParts.add(part);
onDetachBlock(part);
continue;
}
if (TileUtil.getTile(world, partCoord) != part) {
deadParts.add(part);
onDetachBlock(part);
continue;
}
MultiblockLogic logic = (MultiblockLogic) part.getMultiblockLogic();
logic.setUnvisited();
logic.forfeitMultiblockSaveDelegate();
c = part.getCoordinates();
if (referenceCoord == null) {
referenceCoord = c;
referencePart = part;
} else if (c.compareTo(referenceCoord) < 0) {
referenceCoord = c;
referencePart = part;
}
}
connectedParts.removeAll(deadParts);
deadParts.clear();
if (referencePart == null || isEmpty()) {
// There are no valid parts remaining. The entire multiblock was unloaded during a chunk unload. Halt.
shouldCheckForDisconnections = false;
MultiblockRegistry.addDeadController(world, this);
return Collections.emptySet();
} else {
MultiblockLogic logic = (MultiblockLogic) referencePart.getMultiblockLogic();
logic.becomeMultiblockSaveDelegate();
}
// Now visit all connected parts, breadth-first, starting from reference coord's part
IMultiblockComponent part;
LinkedList<IMultiblockComponent> partsToCheck = new LinkedList<>();
partsToCheck.add(referencePart);
while (!partsToCheck.isEmpty()) {
part = partsToCheck.removeFirst();
MultiblockLogic partLogic = (MultiblockLogic) part.getMultiblockLogic();
partLogic.setVisited();
// Chunk-safe on server, but not on client
List<IMultiblockComponent> nearbyParts = MultiblockUtil.getNeighboringParts(world, part);
for (IMultiblockComponent nearbyPart : nearbyParts) {
// Ignore different machines
MultiblockLogic nearbyPartLogic = (MultiblockLogic) nearbyPart.getMultiblockLogic();
if (nearbyPartLogic.getController() != this) {
continue;
}
if (!nearbyPartLogic.isVisited()) {
nearbyPartLogic.setVisited();
partsToCheck.add(nearbyPart);
}
}
}
// Finally, remove all parts that remain disconnected.
Set<IMultiblockComponent> removedParts = new HashSet<>();
for (IMultiblockComponent orphanCandidate : connectedParts) {
MultiblockLogic logic = (MultiblockLogic) orphanCandidate.getMultiblockLogic();
if (!logic.isVisited()) {
deadParts.add(orphanCandidate);
onDetachBlock(orphanCandidate);
removedParts.add(orphanCandidate);
}
}
// Trim any blocks that were invalid, or were removed.
connectedParts.removeAll(deadParts);
// Cleanup. Not necessary, really.
deadParts.clear();
// Juuuust in case.
if (referenceCoord == null) {
selectNewReferenceCoord();
}
// We've run the checks from here on out.
shouldCheckForDisconnections = false;
return removedParts;
}
use of forestry.api.multiblock.IMultiblockComponent in project ForestryMC by ForestryMC.
the class MultiblockControllerBase method selectNewReferenceCoord.
@Nullable
private BlockPos selectNewReferenceCoord() {
IChunkProvider chunkProvider = world.getChunkProvider();
IMultiblockComponent theChosenOne = null;
referenceCoord = null;
for (IMultiblockComponent part : connectedParts) {
BlockPos partCoord = part.getCoordinates();
if (isInvalid(part) || chunkProvider.getLoadedChunk(partCoord.getX() >> 4, partCoord.getZ() >> 4) == null) {
// Chunk is unloading, skip this coord to prevent chunk thrashing
continue;
}
if (referenceCoord == null || referenceCoord.compareTo(partCoord) > 0) {
referenceCoord = part.getCoordinates();
theChosenOne = part;
}
}
if (theChosenOne != null) {
MultiblockLogic logic = (MultiblockLogic) theChosenOne.getMultiblockLogic();
logic.becomeMultiblockSaveDelegate();
}
return referenceCoord;
}
use of forestry.api.multiblock.IMultiblockComponent in project ForestryMC by ForestryMC.
the class MultiblockControllerBase method detachAllBlocks.
@Override
public Set<IMultiblockComponent> detachAllBlocks() {
IChunkProvider chunkProvider = world.getChunkProvider();
for (IMultiblockComponent part : connectedParts) {
BlockPos partCoord = part.getCoordinates();
if (chunkProvider.getLoadedChunk(partCoord.getX() >> 4, partCoord.getZ() >> 4) != null) {
onDetachBlock(part);
}
}
Set<IMultiblockComponent> detachedParts = connectedParts;
connectedParts = new HashSet<>();
return detachedParts;
}
Aggregations