/*
* Copyright 2016 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.internal;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import org.terasology.utilities.Assets;
import org.terasology.math.Rotation;
import org.terasology.math.Side;
import org.terasology.math.geom.Vector2f;
import org.terasology.world.block.Block;
import org.terasology.world.block.BlockAppearance;
import org.terasology.world.block.BlockBuilderHelper;
import org.terasology.world.block.BlockPart;
import org.terasology.world.block.loader.BlockFamilyDefinition;
import org.terasology.world.block.loader.SectionDefinitionData;
import org.terasology.world.block.shapes.BlockMeshPart;
import org.terasology.world.block.shapes.BlockShape;
import org.terasology.world.block.tiles.BlockTile;
import org.terasology.world.block.tiles.WorldAtlas;
import java.util.Map;
public class BlockBuilder implements BlockBuilderHelper {
private WorldAtlas worldAtlas;
private BlockShape cubeShape;
private BlockShape loweredShape;
public BlockBuilder(WorldAtlas worldAtlas) {
this.worldAtlas = worldAtlas;
cubeShape = Assets.get("engine:cube", BlockShape.class).get();
loweredShape = Assets.get("engine:loweredCube", BlockShape.class).get();
}
@Override
public Block constructSimpleBlock(BlockFamilyDefinition definition) {
BlockShape shape = definition.getData().getBaseSection().getShape();
if (shape == null) {
shape = cubeShape;
}
Block block = constructCustomBlock(definition.getUrn().getResourceName().toString(), shape, Rotation.none(), definition.getData().getBaseSection());
// Lowered mesh for liquids
if (block.isLiquid()) {
applyLoweredShape(block, loweredShape, definition.getData().getBaseSection().getBlockTiles());
}
return block;
}
@Override
public Block constructSimpleBlock(BlockFamilyDefinition definition, BlockShape shape) {
return constructCustomBlock(definition.getUrn().getResourceName().toString(), shape, Rotation.none(), definition.getData().getBaseSection());
}
@Override
public Block constructSimpleBlock(BlockFamilyDefinition definition, String section) {
BlockShape shape = definition.getData().getSection(section).getShape();
if (shape == null) {
shape = cubeShape;
}
return constructCustomBlock(definition.getUrn().getResourceName().toString(), shape, Rotation.none(), definition.getData().getSection(section));
}
@Override
public Block constructSimpleBlock(BlockFamilyDefinition definition, BlockShape shape, String section) {
return constructCustomBlock(definition.getUrn().getResourceName().toString(), shape, Rotation.none(), definition.getData().getSection(section));
}
@Override
public Block constructTransformedBlock(BlockFamilyDefinition definition, Rotation rotation) {
BlockShape shape = definition.getData().getBaseSection().getShape();
if (shape == null) {
shape = cubeShape;
}
return constructCustomBlock(definition.getUrn().getResourceName().toString(), shape, rotation, definition.getData().getBaseSection());
}
@Override
public Block constructTransformedBlock(BlockFamilyDefinition definition, String section, Rotation rotation) {
BlockShape shape = definition.getData().getSection(section).getShape();
if (shape == null) {
shape = cubeShape;
}
return constructCustomBlock(definition.getUrn().getResourceName().toString(), shape, rotation, definition.getData().getSection(section));
}
@Override
public Block constructTransformedBlock(BlockFamilyDefinition definition, BlockShape shape, Rotation rotation) {
return constructCustomBlock(definition.getUrn().getResourceName().toString(), shape, rotation, definition.getData().getBaseSection());
}
@Override
public Block constructTransformedBlock(BlockFamilyDefinition definition, BlockShape shape, String section, Rotation rotation) {
return constructCustomBlock(definition.getUrn().getResourceName().toString(), shape, rotation, definition.getData().getSection(section));
}
@Override
public Block constructCustomBlock(String defaultName, BlockShape shape, Rotation rotation, SectionDefinitionData section) {
Block block = createRawBlock(defaultName, section);
block.setDirection(rotation.rotate(Side.FRONT));
block.setPrimaryAppearance(createAppearance(shape, section.getBlockTiles(), rotation));
setBlockFullSides(block, shape, rotation);
block.setCollision(shape.getCollisionOffset(rotation), shape.getCollisionShape(rotation));
for (BlockPart part : BlockPart.values()) {
block.setColorSource(part, section.getColorSources().get(part));
block.setColorOffset(part, section.getColorOffsets().get(part));
}
return block;
}
private Block createRawBlock(String defaultName, SectionDefinitionData def) {
Block block = new Block();
block.setLiquid(def.isLiquid());
block.setWater(def.isWater());
block.setLava(def.isLava());
block.setGrass(def.isGrass());
block.setIce(def.isIce());
block.setHardness(def.getHardness());
block.setAttachmentAllowed(def.isAttachmentAllowed());
block.setReplacementAllowed(def.isReplacementAllowed());
block.setSupportRequired(def.isSupportRequired());
block.setPenetrable(def.isPenetrable());
block.setTargetable(def.isTargetable());
block.setClimbable(def.isClimbable());
block.setTranslucent(def.isTranslucent());
block.setDoubleSided(def.isDoubleSided());
block.setShadowCasting(def.isShadowCasting());
block.setWaving(def.isWaving());
block.setLuminance(def.getLuminance());
block.setTint(def.getTint());
if (Strings.isNullOrEmpty(def.getDisplayName())) {
block.setDisplayName(properCase(defaultName));
} else {
block.setDisplayName(def.getDisplayName());
}
block.setSounds(def.getSounds());
block.setMass(def.getMass());
block.setDebrisOnDestroy(def.isDebrisOnDestroy());
if (def.getEntity() != null) {
block.setPrefab(def.getEntity().getPrefab());
block.setKeepActive(def.getEntity().isKeepActive());
}
if (def.getInventory() != null) {
block.setStackable(def.getInventory().isStackable());
block.setDirectPickup(def.getInventory().isDirectPickup());
}
return block;
}
private BlockAppearance createAppearance(BlockShape shape, Map<BlockPart, BlockTile> tiles, Rotation rot) {
Map<BlockPart, BlockMeshPart> meshParts = Maps.newEnumMap(BlockPart.class);
Map<BlockPart, Vector2f> textureAtlasPositions = Maps.newEnumMap(BlockPart.class);
for (BlockPart part : BlockPart.values()) {
// TODO: Need to be more sensible with the texture atlas. Because things like block particles read from a part that may not exist, we're being fairly lenient
Vector2f atlasPos;
if (tiles.get(part) == null) {
atlasPos = new Vector2f();
} else {
atlasPos = worldAtlas.getTexCoords(tiles.get(part), shape.getMeshPart(part) != null);
}
BlockPart targetPart = part.rotate(rot);
textureAtlasPositions.put(targetPart, atlasPos);
if (shape.getMeshPart(part) != null) {
meshParts.put(targetPart, shape.getMeshPart(part).rotate(rot.getQuat4f()).mapTexCoords(atlasPos, worldAtlas.getRelativeTileSize()));
}
}
return new BlockAppearance(meshParts, textureAtlasPositions);
}
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));
}
}
private void applyLoweredShape(Block block, BlockShape shape, Map<BlockPart, BlockTile> tiles) {
for (Side side : Side.values()) {
BlockPart part = BlockPart.fromSide(side);
BlockTile blockTile = tiles.get(part);
if (blockTile != null) {
BlockMeshPart meshPart = shape
.getMeshPart(part)
.rotate(Rotation.none().getQuat4f())
.mapTexCoords(worldAtlas.getTexCoords(blockTile, true), worldAtlas.getRelativeTileSize());
block.setLoweredLiquidMesh(part.getSide(), meshPart);
}
}
}
private String properCase(String s) {
if (s.length() > 1) {
return s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
} else {
return s.toUpperCase();
}
}
}