/* * Copyright 2014 MovingBlocks * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.terasology.world.block.structure; import org.terasology.entitySystem.entity.EntityRef; import org.terasology.entitySystem.event.ReceiveEvent; import org.terasology.entitySystem.prefab.PrefabManager; import org.terasology.logic.delay.DelayManager; import org.terasology.logic.delay.DelayedActionTriggeredEvent; import org.terasology.logic.health.DestroyEvent; import org.terasology.math.Side; import org.terasology.math.geom.Vector3i; import org.terasology.registry.CoreRegistry; import org.terasology.world.BlockEntityRegistry; import org.terasology.world.WorldProvider; import org.terasology.world.block.Block; import org.terasology.world.block.BlockComponent; import java.util.Collections; import java.util.Map; public class SideBlockSupportRequired implements BlockStructuralSupport { private static final String SUPPORT_CHECK_ACTION_ID = "Engine:SideBlockSupportCheck"; @Override public int getPriority() { return 1000; } @Override public boolean shouldBeRemovedDueToChange(Vector3i location, Side sideChanged) { final SideBlockSupportRequiredComponent component = getComponent(location, Collections.<Vector3i, Block>emptyMap()); if (component != null) { final boolean sufficientlySupported = isSufficientlySupported(location, sideChanged, Collections.<Vector3i, Block>emptyMap(), component); if (!sufficientlySupported) { if (component.dropDelay <= 0) { return true; } else { DelayManager delayManager = CoreRegistry.get(DelayManager.class); final EntityRef blockEntity = getBlockEntityRegistry().getEntityAt(location); if (!delayManager.hasDelayedAction(blockEntity, SUPPORT_CHECK_ACTION_ID)) { delayManager.addDelayedAction(blockEntity, SUPPORT_CHECK_ACTION_ID, component.dropDelay); } } } } return false; } @ReceiveEvent public void checkForSupport(DelayedActionTriggeredEvent event, EntityRef entity, BlockComponent block, SideBlockSupportRequiredComponent supportRequired) { if (event.getActionId().equals(SUPPORT_CHECK_ACTION_ID)) { if (!isSufficientlySupported(block.getPosition(), null, Collections.<Vector3i, Block>emptyMap(), supportRequired)) { PrefabManager prefabManager = CoreRegistry.get(PrefabManager.class); entity.send(new DestroyEvent(entity, EntityRef.NULL, prefabManager.getPrefab("engine:supportRemovedDamage"))); } } } @Override public boolean isSufficientlySupported(Vector3i location, Map<Vector3i, Block> blockOverrides) { final SideBlockSupportRequiredComponent component = getComponent(location, blockOverrides); if (component != null) { return isSufficientlySupported(location, null, blockOverrides, component); } return true; } private EntityRef getEntity(Vector3i location, Map<Vector3i, Block> blockOverrides) { final Block overwrittenBlock = blockOverrides.get(location); if (overwrittenBlock != null) { return overwrittenBlock.getEntity(); } EntityRef blockEntity = getBlockEntityRegistry().getExistingBlockEntityAt(location); if (blockEntity.exists()) { return blockEntity; } else { return getWorldProvider().getBlock(location).getEntity(); } } private SideBlockSupportRequiredComponent getComponent(Vector3i location, Map<Vector3i, Block> blockOverrides) { return getEntity(location, blockOverrides).getComponent(SideBlockSupportRequiredComponent.class); } private boolean isSufficientlySupported(Vector3i location, Side sideChanged, Map<Vector3i, Block> blockOverrides, SideBlockSupportRequiredComponent supportComponent) { if (supportComponent != null) { if ((sideChanged == null || sideChanged.isHorizontal()) && supportComponent.sideAllowed && !hasSupport(location, supportComponent, blockOverrides)) { return false; } else if ((sideChanged == null || !sideChanged.isHorizontal()) && (supportComponent.topAllowed || supportComponent.bottomAllowed) && !hasSupport(location, supportComponent, blockOverrides)) { return false; } } return true; } private boolean hasSupport(Vector3i blockPosition, SideBlockSupportRequiredComponent supportComponent, Map<Vector3i, Block> blockOverrides) { if (supportComponent.bottomAllowed && hasSupportFromBlockOnSide(blockPosition, Side.BOTTOM, blockOverrides)) { return true; } if (supportComponent.topAllowed && hasSupportFromBlockOnSide(blockPosition, Side.TOP, blockOverrides)) { return true; } if (supportComponent.sideAllowed && (hasSupportFromBlockOnSide(blockPosition, Side.LEFT, blockOverrides) || hasSupportFromBlockOnSide(blockPosition, Side.RIGHT, blockOverrides) || hasSupportFromBlockOnSide(blockPosition, Side.FRONT, blockOverrides) || hasSupportFromBlockOnSide(blockPosition, Side.BACK, blockOverrides))) { return true; } return false; } private boolean hasSupportFromBlockOnSide(Vector3i blockPosition, Side side, Map<Vector3i, Block> blockOverrides) { final Vector3i sideBlockPosition = side.getAdjacentPos(blockPosition); if (!getWorldProvider().isBlockRelevant(sideBlockPosition)) { return true; } return getBlockWithOverrides(sideBlockPosition, blockOverrides).canAttachTo(side.reverse()); } private Block getBlockWithOverrides(Vector3i location, Map<Vector3i, Block> blockOverrides) { final Block blockFromOverride = blockOverrides.get(location); if (blockFromOverride != null) { return blockFromOverride; } return getWorldProvider().getBlock(location); } private BlockEntityRegistry getBlockEntityRegistry() { return CoreRegistry.get(BlockEntityRegistry.class); } private WorldProvider getWorldProvider() { return CoreRegistry.get(WorldProvider.class); } }