public static boolean areNodesConnecting(NetworkNode node1, NetworkNode node2) { for (Side side : SideBitFlag.getSides(node1.connectionSides)) { final ImmutableBlockLocation possibleConnectedLocation = node1.location.move(side); if (node2.location.equals(possibleConnectedLocation) && SideBitFlag.hasSide(node2.connectionSides, side.reverse())) return true; } return false; }
private void updateAdjacentChunksReadyFieldOfAdjChunks(Chunk chunkInCenter) { Vector3i centerChunkPos = chunkInCenter.getPosition(); for (Side side : Side.values()) { Vector3i adjChunkPos = side.getAdjacentPos(centerChunkPos); Chunk adjChunk = nearCache.get(adjChunkPos); if (adjChunk != null) { updateAdjacentChunksReadyFieldOf(adjChunk); } } }
private boolean canConnectToNetworkingNode(NetworkNode networkNode) { for (Side connectingOnSide : SideBitFlag.getSides(networkNode.connectionSides)) { final ImmutableBlockLocation possibleConnectionLocation = networkNode.location.move(connectingOnSide); for (NetworkNode possibleConnectedNode : networkingNodes.get(possibleConnectionLocation)) { if (SideBitFlag.hasSide(possibleConnectedNode.connectionSides, connectingOnSide.reverse())) return true; } } return false; }
private void listConnectedNotVisitedNetworkingNodes( Set<NetworkNode> visitedNodes, NetworkNode location, Collection<NetworkNode> result) { for (Side connectingOnSide : SideBitFlag.getSides(location.connectionSides)) { final ImmutableBlockLocation possibleConnectionLocation = location.location.move(connectingOnSide); for (NetworkNode possibleConnection : networkingNodes.get(possibleConnectionLocation)) { if (!visitedNodes.contains(possibleConnection) && SideBitFlag.hasSide(possibleConnection.connectionSides, connectingOnSide.reverse())) result.add(possibleConnection); } } }
private boolean areAdjacentChunksReady(Chunk chunk) { Vector3i centerChunkPos = chunk.getPosition(); for (Side side : Side.values()) { Vector3i adjChunkPos = side.getAdjacentPos(centerChunkPos); Chunk adjChunk = nearCache.get(adjChunkPos); boolean adjChunkReady = (adjChunk != null && adjChunk.isReady()); if (!adjChunkReady) { return false; } } return true; }
/** * Returns true if the side should be rendered adjacent to the second side provided. * * @param blockToCheck The block to check * @param currentBlock The current block * @return True if the side is visible for the given block types */ private boolean isSideVisibleForBlockTypes(Block blockToCheck, Block currentBlock, Side side) { // Liquids can be transparent but there should be no visible adjacent faces if (currentBlock.isLiquid() && blockToCheck.isLiquid()) { return false; } return currentBlock.isWaving() != blockToCheck.isWaving() || blockToCheck.isInvisible() || !blockToCheck.isFullSide(side.reverse()) || (!currentBlock.isTranslucent() && blockToCheck.isTranslucent()); }
private void applyLoweredShape(Block block, BlockShape shape, Map<BlockPart, AssetUri> tileUris) { for (Side side : Side.values()) { BlockPart part = BlockPart.fromSide(side); BlockMeshPart meshPart = shape .getMeshPart(part) .rotate(Rotation.none().getQuat4f()) .mapTexCoords( atlas.getTexCoords(tileUris.get(part), true), atlas.getRelativeTileSize()); block.setLoweredLiquidMesh(part.getSide(), meshPart); } }
@Override public boolean isConnectingTo( Vector3i blockLocation, Side connectSide, WorldProvider worldProvider, BlockEntityRegistry blockEntityRegistry) { Vector3i neighborLocation = new Vector3i(blockLocation); neighborLocation.add(connectSide.getVector3i()); EntityRef neighborEntity = blockEntityRegistry.getBlockEntityAt(neighborLocation); return neighborEntity != null && connectsToNeighbor(neighborEntity); }
@Override public byte getLeafSidesInNetwork(NetworkNode networkNode) { if (!hasLeafNode(networkNode)) throw new IllegalArgumentException("Cannot test nodes not in network"); if (networkingNodes.size() == 0) { // Degenerated network for (Side connectingOnSide : SideBitFlag.getSides(networkNode.connectionSides)) { Vector3i possibleLocation = networkNode.location.toVector3i(); possibleLocation.add(connectingOnSide.getVector3i()); for (NetworkNode node : leafNodes.get(new ImmutableBlockLocation(possibleLocation))) { if (SideBitFlag.hasSide(node.connectionSides, connectingOnSide.reverse())) { return SideBitFlag.getSide(connectingOnSide); } } } return 0; } else { byte result = 0; for (Side connectingOnSide : SideBitFlag.getSides(networkNode.connectionSides)) { Vector3i possibleLocation = networkNode.location.toVector3i(); possibleLocation.add(connectingOnSide.getVector3i()); for (NetworkNode node : networkingNodes.get(new ImmutableBlockLocation(possibleLocation))) { if (SideBitFlag.hasSide(node.connectionSides, connectingOnSide.reverse())) { result += SideBitFlag.getSide(connectingOnSide); } } } return result; } }
public static <T> void deserializeBlockPartMap( EnumMap<BlockPart, T> target, JsonObject jsonObj, Class<T> type, JsonDeserializationContext context) { if (jsonObj.has("all")) { T value = context.deserialize(jsonObj.get("all"), type); for (BlockPart part : BlockPart.values()) { target.put(part, value); } } if (jsonObj.has("sides")) { T value = context.deserialize(jsonObj.get("sides"), type); for (Side side : Side.horizontalSides()) { target.put(BlockPart.fromSide(side), value); } } if (jsonObj.has("topBottom")) { T value = context.deserialize(jsonObj.get("topBottom"), type); target.put(BlockPart.TOP, value); target.put(BlockPart.BOTTOM, value); } if (jsonObj.has("top")) { T value = context.deserialize(jsonObj.get("top"), type); target.put(BlockPart.TOP, value); } if (jsonObj.has("bottom")) { T value = context.deserialize(jsonObj.get("bottom"), type); target.put(BlockPart.BOTTOM, value); } if (jsonObj.has("front")) { T value = context.deserialize(jsonObj.get("front"), type); target.put(BlockPart.FRONT, value); } if (jsonObj.has("back")) { T value = context.deserialize(jsonObj.get("back"), type); target.put(BlockPart.BACK, value); } if (jsonObj.has("left")) { T value = context.deserialize(jsonObj.get("left"), type); target.put(BlockPart.LEFT, value); } if (jsonObj.has("right")) { T value = context.deserialize(jsonObj.get("right"), type); target.put(BlockPart.RIGHT, value); } if (jsonObj.has("center")) { T value = context.deserialize(jsonObj.get("center"), type); target.put(BlockPart.CENTER, value); } }
/** * @param name The name for the block group. * @param blocks The set of blocks that make up the group. Front, Back, Left and Right must be * provided - the rest is ignored. */ public AlignToSurfaceFamily(String name, EnumMap<Side, Block> blocks) { _name = name; for (Side side : Side.values()) { Block block = blocks.get(side); if (block != null) { _blocks.put(side, block); block.withBlockFamily(this); } } if (_blocks.containsKey(Side.TOP)) { _archetype = _blocks.get(Side.TOP); } else { _archetype = _blocks.get(Side.FRONT); } }
@Override protected void doReload(BlockShapeData data) { collisionShape.clear(); displayName = data.getDisplayName(); for (BlockPart part : BlockPart.values()) { this.meshParts.put(part, data.getMeshPart(part)); } for (Side side : Side.values()) { this.fullSide.put(side, data.isBlockingSide(side)); } this.baseCollisionShape = data.getCollisionShape(); this.baseCollisionOffset.set(data.getCollisionOffset()); collisionShape.put(Rotation.none(), baseCollisionShape); yawSymmetric = data.isYawSymmetric(); pitchSymmetric = data.isPitchSymmetric(); rollSymmetric = data.isRollSymmetric(); }
@Override public void generateChunkMesh(ChunkView view, ChunkMesh chunkMesh, int x, int y, int z) { Biome selfBiome = view.getBiome(x, y, z); Block selfBlock = view.getBlock(x, y, z); // TODO: Needs review - too much hardcoded special cases and corner cases resulting from this. ChunkVertexFlag vertexFlag = ChunkVertexFlag.NORMAL; if (selfBlock.isWater()) { if (view.getBlock(x, y + 1, z).isWater()) { vertexFlag = ChunkVertexFlag.WATER; } else { vertexFlag = ChunkVertexFlag.WATER_SURFACE; } } else if (selfBlock.isLava()) { vertexFlag = ChunkVertexFlag.LAVA; } else if (selfBlock.isWaving() && selfBlock.isDoubleSided()) { vertexFlag = ChunkVertexFlag.WAVING; } else if (selfBlock.isWaving()) { vertexFlag = ChunkVertexFlag.WAVING_BLOCK; } // Gather adjacent blocks Map<Side, Block> adjacentBlocks = Maps.newEnumMap(Side.class); for (Side side : Side.values()) { Vector3i offset = side.getVector3i(); Block blockToCheck = view.getBlock(x + offset.x, y + offset.y, z + offset.z); adjacentBlocks.put(side, blockToCheck); } BlockAppearance blockAppearance = selfBlock.getAppearance(adjacentBlocks); /* * Determine the render process. */ ChunkMesh.RenderType renderType = ChunkMesh.RenderType.TRANSLUCENT; if (!selfBlock.isTranslucent()) { renderType = ChunkMesh.RenderType.OPAQUE; } // TODO: Review special case, or alternatively compare uris. if (selfBlock.isWater() || selfBlock.isIce()) { renderType = ChunkMesh.RenderType.WATER_AND_ICE; } if (selfBlock.isDoubleSided()) { renderType = ChunkMesh.RenderType.BILLBOARD; } if (blockAppearance.getPart(BlockPart.CENTER) != null) { Vector4f colorOffset = selfBlock.calcColorOffsetFor(BlockPart.CENTER, selfBiome); blockAppearance .getPart(BlockPart.CENTER) .appendTo(chunkMesh, x, y, z, colorOffset, renderType, vertexFlag); } boolean[] drawDir = new boolean[6]; for (Side side : Side.values()) { drawDir[side.ordinal()] = blockAppearance.getPart(BlockPart.fromSide(side)) != null && isSideVisibleForBlockTypes(adjacentBlocks.get(side), selfBlock, side); } // If the selfBlock is lowered, some more faces may have to be drawn if (selfBlock.isLiquid()) { Block bottomBlock = adjacentBlocks.get(Side.BOTTOM); // Draw horizontal sides if visible from below for (Side side : Side.horizontalSides()) { Vector3i offset = side.getVector3i(); Block adjacentBelow = view.getBlock(x + offset.x, y - 1, z + offset.z); Block adjacent = adjacentBlocks.get(side); boolean visible = (blockAppearance.getPart(BlockPart.fromSide(side)) != null && isSideVisibleForBlockTypes(adjacentBelow, selfBlock, side) && !isSideVisibleForBlockTypes(bottomBlock, adjacent, side.reverse())); drawDir[side.ordinal()] |= visible; } // Draw the top if below a non-lowered selfBlock // TODO: Don't need to render the top if each side and the selfBlock above each side are // either liquid or opaque solids. Block blockToCheck = adjacentBlocks.get(Side.TOP); drawDir[Side.TOP.ordinal()] |= !blockToCheck.isLiquid(); if (bottomBlock.isLiquid() || bottomBlock.isInvisible()) { for (Side dir : Side.values()) { if (drawDir[dir.ordinal()]) { Vector4f colorOffset = selfBlock.calcColorOffsetFor(BlockPart.fromSide(dir), selfBiome); selfBlock .getLoweredLiquidMesh(dir) .appendTo(chunkMesh, x, y, z, colorOffset, renderType, vertexFlag); } } return; } } for (Side dir : Side.values()) { if (drawDir[dir.ordinal()]) { Vector4f colorOffset = selfBlock.calcColorOffsetFor(BlockPart.fromSide(dir), selfBiome); // TODO: Needs review since the new per-vertex flags introduce a lot of special scenarios - // probably a per-side setting? if (selfBlock.isGrass() && dir != Side.TOP && dir != Side.BOTTOM) { blockAppearance .getPart(BlockPart.fromSide(dir)) .appendTo(chunkMesh, x, y, z, colorOffset, renderType, ChunkVertexFlag.COLOR_MASK); } else { // if(dir == Side.TOP) logger.info("Generating: " + (new Vector3i(x, y, z)).toString() + " // " + view.getChunkRegion().toString() + " " + dir.toString()); blockAppearance .getPart(BlockPart.fromSide(dir)) .appendTo(chunkMesh, x, y, z, colorOffset, renderType, vertexFlag); } } } }
private void setBlockFullSides(Block block, BlockShape shape, Rotation rot) { for (Side side : Side.values()) { BlockPart targetPart = BlockPart.fromSide(rot.rotate(side)); block.setFullSide(targetPart.getSide(), shape.isBlockingSide(side)); } }