Skip to content

Commit

Permalink
fixed connection issues with new block families
Browse files Browse the repository at this point in the history
  • Loading branch information
pollend committed Jun 9, 2018
1 parent bef7cd7 commit 0c5ca9a
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 75 deletions.
99 changes: 24 additions & 75 deletions src/main/java/org/terasology/minecarts/blocks/RailBlockFamily.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package org.terasology.minecarts.blocks;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import gnu.trove.map.TByteObjectMap;
import gnu.trove.map.hash.TByteObjectHashMap;
Expand All @@ -35,15 +34,11 @@
import org.terasology.world.block.family.BlockSections;
import org.terasology.world.block.family.MultiConnectFamily;
import org.terasology.world.block.family.RegisterBlockFamily;
import org.terasology.world.block.family.UpdatesWithNeighboursFamily;
import org.terasology.world.block.loader.BlockFamilyDefinition;
import org.terasology.world.block.shapes.BlockShape;

import javax.print.attribute.standard.Sides;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.*;

@RegisterBlockFamily("rails")
@BlockSections({"no_connections", "one_connection", "one_connection_slope", "line_connection", "2d_corner", "2d_t", "cross"})
Expand All @@ -69,7 +64,7 @@ public RailBlockFamily(BlockFamilyDefinition definition, BlockBuilderHelper bloc

this.registerBlock(blockUri,definition,blockBuilder,NO_CONNECTIONS, (byte) 0, Rotation.horizontalRotations());
this.registerBlock(blockUri,definition,blockBuilder,ONE_CONNECTION, SideBitFlag.getSides(Side.RIGHT), Rotation.horizontalRotations());
this.registerBlock(blockUri,definition,blockBuilder,ONE_CONNECTIONS_SLOPE, SideBitFlag.getSides(Side.BACK, Side.TOP), Rotation.horizontalRotations());
this.registerBlock(blockUri,definition,blockBuilder,ONE_CONNECTIONS_SLOPE, SideBitFlag.getSides(Side.FRONT, Side.TOP), Rotation.horizontalRotations());
this.registerBlock(blockUri,definition,blockBuilder,TWO_CONNECTIONS_LINE, SideBitFlag.getSides(Side.LEFT, Side.RIGHT), Rotation.horizontalRotations());
this.registerBlock(blockUri,definition,blockBuilder,TWO_CONNECTIONS_CORNER, SideBitFlag.getSides(Side.LEFT, Side.FRONT), Rotation.horizontalRotations());
this.registerBlock(blockUri,definition,blockBuilder,THREE_CONNECTIONS_T, SideBitFlag.getSides(Side.LEFT, Side.RIGHT, Side.FRONT), Rotation.horizontalRotations());
Expand All @@ -94,94 +89,48 @@ public Set<Block> registerBlock(BlockUri root, BlockFamilyDefinition definition,

@Override
public Block getBlockForPlacement(Vector3i location, Side attachmentSide, Side direction) {
return blocks.get(getByteConnections(location));
}

private byte getByteConnections(Vector3i location) {
byte connections = 0;
byte fullConnectedEdges = 0;
int countConnetions = 0;
boolean hasTopBlock = false;
ArrayList<Side> skipSides = new ArrayList<Side>();
Vector3i upLocation = new Vector3i(location);
upLocation.y += 1;
Block block = worldProvider.getBlock(upLocation);

if (block.getURI() != BlockManager.AIR_ID && !block.isPenetrable() && block.isLiquid()) {
hasTopBlock = true;
}

for (Side connectSide : Side.values()) {
if (connectionCondition(location, connectSide)) {
if (isFullyConnected(location, connectSide, worldProvider, blockEntityRegistry))
fullConnectedEdges += SideBitFlag.getSide(connectSide);
else
connections += SideBitFlag.getSide(connectSide);

} else if (hasTopBlock) {
block = worldProvider.getBlock(location);

if (block.getURI() != BlockManager.AIR_ID && !block.isPenetrable() && block.isLiquid()) {
skipSides.add(connectSide);
}
for (Side connectSide : SideBitFlag.getSides(getConnectionSides())) {
if (this.connectionCondition(location, connectSide) && !isFullyConnected(location,connectSide)) {
connections |= SideBitFlag.getSide(connectSide);
}
}
if (connections == 0)
connections = fullConnectedEdges;

countConnetions = SideBitFlag.getSides(connections).size();

upLocation.y -= 2;
for (Side connectSide : Side.values()) {
if (connectionCondition(upLocation, connectSide)) {
connections += SideBitFlag.getSide(connectSide);
for (Side connectSide : SideBitFlag.getSides(getConnectionSides())) {
if (this.connectionCondition(new Vector3i(location).add(Vector3i.down()), connectSide)) {
connections |= SideBitFlag.getSide(connectSide);
}
}
upLocation.y += 2;
switch (countConnetions) {
case 0:
for (Side connectSide : Side.values()) {
if (skipSides.contains(connectSide)) {
continue;
}
if (connectionCondition(upLocation, connectSide)) {
connections = 0;
connections += SideBitFlag.getSide(connectSide);
connections += SideBitFlag.getSide(Side.TOP);
break;
}
}
break;
case 1:
EnumSet<Side> sides = SideBitFlag.getSides(connections);
Side connectSide = (Side) sides.toArray()[0];
connectSide = connectSide.reverse();
if (skipSides.contains(connectSide)) {
break;
}

if (connectionCondition(upLocation,connectSide)) {
connections = 0;
connections += SideBitFlag.getSide(connectSide);
connections += SideBitFlag.getSide(Side.TOP);
break;
for (Side connectSide : SideBitFlag.getSides(getConnectionSides())) {
if (this.connectionCondition(new Vector3i(location).add(Vector3i.up()), connectSide)) {
connections |= SideBitFlag.getSide(Side.TOP);
if(SideBitFlag.getSides(connections).size() == 1){
connections |= SideBitFlag.getSide(connectSide.reverse());
}
break;
}
}
return connections;
return blocks.get(connections);
}



@Override
public Block getBlockForNeighborUpdate(Vector3i location, Block oldBlock) {
return oldBlock;
}



/**
* a fully connected tile has more then 1 connected edge and is not attached to the reference tile
*
* @param location
* @param connectSide
* @param worldProvider
* @param blockEntityRegistry
* @return
*/
private boolean isFullyConnected(Vector3i location, Side connectSide, WorldProvider worldProvider, BlockEntityRegistry blockEntityRegistry) {
private boolean isFullyConnected(Vector3i location, Side connectSide) {
if (connectionCondition(location, connectSide)) {
Vector3i neighborLocation = new Vector3i(location);
neighborLocation.add(connectSide.getVector3i());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
* Copyright 2015 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.minecarts.blocks;

import com.google.common.collect.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.entitySystem.event.EventPriority;
import org.terasology.entitySystem.event.ReceiveEvent;
import org.terasology.entitySystem.systems.BaseComponentSystem;
import org.terasology.entitySystem.systems.RegisterMode;
import org.terasology.entitySystem.systems.RegisterSystem;
import org.terasology.entitySystem.systems.UpdateSubscriberSystem;
import org.terasology.logic.common.ActivateEvent;
import org.terasology.logic.health.DoDamageEvent;
import org.terasology.logic.health.DoDestroyEvent;
import org.terasology.logic.health.EngineDamageTypes;
import org.terasology.logic.inventory.ItemComponent;
import org.terasology.math.Side;
import org.terasology.math.SideBitFlag;
import org.terasology.math.geom.Vector3i;
import org.terasology.registry.In;
import org.terasology.world.BlockEntityRegistry;
import org.terasology.world.OnChangedBlock;
import org.terasology.world.WorldProvider;
import org.terasology.world.block.Block;
import org.terasology.world.block.BlockComponent;
import org.terasology.world.block.BlockManager;
import org.terasology.world.block.entity.neighbourUpdate.LargeBlockUpdateFinished;
import org.terasology.world.block.entity.neighbourUpdate.LargeBlockUpdateStarting;
import org.terasology.world.block.items.BlockItemComponent;
import org.terasology.world.block.items.OnBlockItemPlaced;

import java.util.Set;

@RegisterSystem(RegisterMode.AUTHORITY)
public class RailsBlockFamilyUpdateSystem extends BaseComponentSystem implements UpdateSubscriberSystem {
private static final Logger logger = LoggerFactory.getLogger(RailsBlockFamilyUpdateSystem.class);

@In
private WorldProvider worldProvider;
@In
private BlockEntityRegistry blockEntityRegistry;
@In
private BlockManager blockManager;

private int largeBlockUpdateCount;
private Set<Vector3i> blocksUpdatedInLargeBlockUpdate = Sets.newHashSet();
private int[] checkOnHeight = {-1, 0, 1};

@ReceiveEvent
public void largeBlockUpdateStarting(LargeBlockUpdateStarting event, EntityRef entity) {
largeBlockUpdateCount++;
}

@ReceiveEvent
public void largeBlockUpdateFinished(LargeBlockUpdateFinished event, EntityRef entity) {
largeBlockUpdateCount--;
if (largeBlockUpdateCount < 0) {
largeBlockUpdateCount = 0;
throw new IllegalStateException("LargeBlockUpdateFinished invoked too many times");
}

if (largeBlockUpdateCount == 0) {
notifyNeighboursOfChangedBlocks();
}
}

@ReceiveEvent()
public void doDestroy(DoDestroyEvent event, EntityRef entity, BlockComponent blockComponent) {
Vector3i upBlock = new Vector3i(blockComponent.getPosition());
upBlock.y += 1;
Block block = worldProvider.getBlock(upBlock);

if (block.getBlockFamily() instanceof RailBlockFamily) {
blockEntityRegistry.getEntityAt(upBlock).send(new DoDamageEvent(1000, EngineDamageTypes.DIRECT.get()));
}
}

//prevents rails from being stacked on top of each other.
@ReceiveEvent(components = {BlockItemComponent.class, ItemComponent.class}, priority = EventPriority.PRIORITY_HIGH)
public void onBlockActivated(ActivateEvent event, EntityRef item) {
BlockComponent blockComponent = event.getTarget().getComponent(BlockComponent.class);
if (blockComponent == null)
return;

Vector3i targetBlock = blockComponent.getPosition();
Block centerBlock = worldProvider.getBlock(targetBlock.x, targetBlock.y, targetBlock.z);

if (centerBlock.getBlockFamily() instanceof RailBlockFamily) {
event.consume();
}
}

@ReceiveEvent(components = {BlockItemComponent.class, ItemComponent.class})
public void onPlaceBlock(OnBlockItemPlaced event, EntityRef entity) {
BlockComponent blockComponent = event.getPlacedBlock().getComponent(BlockComponent.class);
if (blockComponent == null)
return;

Vector3i targetBlock = blockComponent.getPosition();
Block centerBlock = worldProvider.getBlock(targetBlock.x, targetBlock.y, targetBlock.z);

if (centerBlock.getBlockFamily() instanceof RailBlockFamily) {
processUpdateForBlockLocation(targetBlock);
}

}

private void notifyNeighboursOfChangedBlocks() {
// Invoke the updates in another large block change for this class only
largeBlockUpdateCount++;
while (!blocksUpdatedInLargeBlockUpdate.isEmpty()) {
Set<Vector3i> blocksToUpdate = blocksUpdatedInLargeBlockUpdate;

// Setup new collection for blocks changed in this pass
blocksUpdatedInLargeBlockUpdate = Sets.newHashSet();

for (Vector3i blockLocation : blocksToUpdate) {
processUpdateForBlockLocation(blockLocation);
}
}
largeBlockUpdateCount--;
}

@ReceiveEvent(components = {BlockComponent.class})
public void blockUpdate(OnChangedBlock event, EntityRef blockEntity) {
if (largeBlockUpdateCount > 0) {
blocksUpdatedInLargeBlockUpdate.add(event.getBlockPosition());
} else {
Vector3i blockLocation = event.getBlockPosition();
processUpdateForBlockLocation(blockLocation);
}
}

private void processUpdateForBlockLocation(Vector3i blockLocation) {
for (int height : checkOnHeight) {
for (Side side : Side.horizontalSides()) {
Vector3i neighborLocation = new Vector3i(blockLocation);
neighborLocation.add(side.getVector3i());
neighborLocation.y += height;
Block neighborBlock = worldProvider.getBlock(neighborLocation);
EntityRef blockEntity = blockEntityRegistry.getBlockEntityAt(neighborLocation);
if (blockEntity.hasComponent(RailComponent.class)) {
RailBlockFamily railsFamily = (RailBlockFamily) neighborBlock.getBlockFamily();
Block neighborBlockAfterUpdate = railsFamily.getBlockForPlacement(neighborLocation, null,null);
if (neighborBlock != neighborBlockAfterUpdate && neighborBlockAfterUpdate != null) {
byte connections = Byte.parseByte(neighborBlock.getURI().getIdentifier().toString());
//only add segment with two connections
if (SideBitFlag.getSides(connections).size() <= 1)
worldProvider.setBlock(neighborLocation, neighborBlockAfterUpdate);
}
}
}
}
}

@Override
public void update(float delta) {
if (largeBlockUpdateCount > 0) {
logger.error("Unmatched LargeBlockUpdateStarted - LargeBlockUpdateFinished not invoked enough times");
}
largeBlockUpdateCount = 0;
}
}

0 comments on commit 0c5ca9a

Please sign in to comment.