Search in sources :

Example 1 with IMultiblockComponent

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());
}
Also used : BlockPos(net.minecraft.util.math.BlockPos) IMultiblockComponent(forestry.api.multiblock.IMultiblockComponent) HashSet(java.util.HashSet)

Example 2 with IMultiblockComponent

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);
    }
}
Also used : BlockPos(net.minecraft.util.math.BlockPos) IMultiblockComponent(forestry.api.multiblock.IMultiblockComponent)

Example 3 with IMultiblockComponent

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;
}
Also used : IChunkProvider(net.minecraft.world.chunk.IChunkProvider) BlockPos(net.minecraft.util.math.BlockPos) IMultiblockComponent(forestry.api.multiblock.IMultiblockComponent) LinkedList(java.util.LinkedList) HashSet(java.util.HashSet)

Example 4 with IMultiblockComponent

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;
}
Also used : IChunkProvider(net.minecraft.world.chunk.IChunkProvider) BlockPos(net.minecraft.util.math.BlockPos) IMultiblockComponent(forestry.api.multiblock.IMultiblockComponent) Nullable(javax.annotation.Nullable)

Example 5 with IMultiblockComponent

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;
}
Also used : IChunkProvider(net.minecraft.world.chunk.IChunkProvider) BlockPos(net.minecraft.util.math.BlockPos) IMultiblockComponent(forestry.api.multiblock.IMultiblockComponent)

Aggregations

IMultiblockComponent (forestry.api.multiblock.IMultiblockComponent)22 BlockPos (net.minecraft.util.math.BlockPos)13 TileEntity (net.minecraft.tileentity.TileEntity)7 ICamouflagedTile (forestry.api.core.ICamouflagedTile)6 HashSet (java.util.HashSet)6 IChunkProvider (net.minecraft.world.chunk.IChunkProvider)6 ICamouflageHandler (forestry.api.core.ICamouflageHandler)4 IMultiblockController (forestry.api.multiblock.IMultiblockController)4 Nullable (javax.annotation.Nullable)3 IMultiblockLogic (forestry.api.multiblock.IMultiblockLogic)2 ArrayList (java.util.ArrayList)2 LinkedList (java.util.LinkedList)2 List (java.util.List)2 Set (java.util.Set)2 ItemStack (net.minecraft.item.ItemStack)2 HashMultiset (com.google.common.collect.HashMultiset)1 Multiset (com.google.common.collect.Multiset)1 GameProfile (com.mojang.authlib.GameProfile)1 MultiblockValidationException (forestry.core.multiblock.MultiblockValidationException)1 TileUtil (forestry.core.tiles.TileUtil)1