use of org.pepsoft.minecraft.Material in project WorldPainter by Captain-Chaos.
the class MixedMaterialTest method testBlobs.
@Test
public void testBlobs() {
try {
System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out), true, "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new InternalError("VM does not support mandatory encoding UTF-8");
}
MixedMaterial mixedMaterial = new MixedMaterial("Test", new Row[] { new Row(DIRT, 400, 1.0f), new Row(GRAVEL, 300, 1.0f), new Row(STONE, 200, 1.0f), new Row(SOUL_SAND, 100, 1.0f) }, -1, null);
long[] buckets = new long[256];
for (int x = 0; x < 500; x++) {
for (int y = 0; y < 500; y++) {
for (int z = 0; z < 256; z++) {
Material material = mixedMaterial.getMaterial(0, x, y, z);
Assert.assertTrue(material == DIRT || material == GRAVEL || material == STONE || material == SOUL_SAND);
buckets[material.blockType]++;
}
}
System.out.println(x);
}
long total = 500L * 500L * 256L;
int dirtPerMillage = (int) (buckets[BLK_DIRT] * 1000L / total);
int gravelPerMillage = (int) (buckets[BLK_GRAVEL] * 1000L / total);
int stonePerMillage = (int) (buckets[BLK_STONE] * 1000L / total);
int soulSandPerMillage = (int) (buckets[BLK_SOUL_SAND] * 1000L / total);
System.out.println("Total blocks tested: " + total);
System.out.println("Dirt: " + dirtPerMillage + "‰");
System.out.println("Gravel: " + gravelPerMillage + "‰");
System.out.println("Stone: " + stonePerMillage + "‰");
System.out.println("Soul sand: " + soulSandPerMillage + "‰");
}
use of org.pepsoft.minecraft.Material in project WorldPainter by Captain-Chaos.
the class TreeType method addVine.
private boolean addVine(MinecraftWorld world, int x, int y, int z, Direction direction) {
Material existingBlock = world.getMaterialAt(x, y, z);
if ((existingBlock == null) || ((existingBlock != AIR) && (existingBlock.blockType != BLK_VINES))) {
return false;
}
int data = existingBlock.data;
switch(direction) {
case NORTH:
data |= 0x4;
break;
case EAST:
data |= 0x8;
break;
case SOUTH:
data |= 0x1;
break;
case WEST:
data |= 0x2;
break;
}
if (existingBlock == AIR) {
world.setBlockTypeAt(x, y, z, BLK_VINES);
}
world.setDataAt(x, y, z, data);
return true;
}
use of org.pepsoft.minecraft.Material in project WorldPainter by Captain-Chaos.
the class CustomMaterialDialog method init.
private void init(MixedMaterial mixedMaterial) {
programmaticChange = true;
try {
biome = mixedMaterial.getBiome();
fieldName.setText(mixedMaterial.getName());
tableModel = new MixedMaterialTableModel(mixedMaterial);
tableModel.addTableModelListener(e -> {
if ((!checkBoxColour.isSelected()) && isExtendedBlockIds()) {
checkBoxColour.setSelected(true);
}
setControlStates();
updateName();
schedulePreviewUpdate();
});
switch(mixedMaterial.getMode()) {
case SIMPLE:
jTabbedPane1.setSelectedIndex(0);
Material simpleMaterial = mixedMaterial.getRows()[0].material;
comboBoxSimpleBlockID.setSelectedIndex(simpleMaterial.blockType);
spinnerSimpleDataValue.setValue(simpleMaterial.data);
break;
case NOISE:
jTabbedPane1.setSelectedIndex(1);
radioButtonNoise.setSelected(true);
break;
case BLOBS:
jTabbedPane1.setSelectedIndex(1);
radioButtonBlobs.setSelected(true);
spinnerScale.setValue((int) (mixedMaterial.getScale() * 100 + 0.5f));
break;
case LAYERED:
jTabbedPane1.setSelectedIndex(1);
radioButtonLayered.setSelected(true);
checkBoxLayeredRepeat.setSelected(mixedMaterial.isRepeat());
if (mixedMaterial.getVariation() != null) {
noiseSettingsEditorLayeredVariation.setNoiseSettings(mixedMaterial.getVariation());
}
spinnerLayeredXAngle.setValue(-(int) Math.round(Math.atan(mixedMaterial.getLayerXSlope()) * DEGREES_TO_RADIANS));
spinnerLayeredYAngle.setValue(-(int) Math.round(Math.atan(mixedMaterial.getLayerYSlope()) * DEGREES_TO_RADIANS));
break;
}
tableMaterialRows.setModel(tableModel);
previousCalculatedName = createName();
selectedColour = (mixedMaterial.getColour() != null) ? mixedMaterial.getColour() : Color.ORANGE.getRGB();
checkBoxColour.setSelected(mixedMaterial.getColour() != null);
setControlStates();
updatePreview();
configureTable();
} finally {
programmaticChange = false;
}
}
use of org.pepsoft.minecraft.Material in project WorldPainter by Captain-Chaos.
the class WPObjectExporter method renderObject.
/**
* Export an object to the world, optionally taking into account the blocks
* that are already there.
*
* @param world The Minecraft world to which to export the object.
* @param dimension The dimension corresponding to the exported world, used
* to determine the terrain height.
* @param object The object to export.
* @param x The X coordinate at which to export the object.
* @param y The Y coordinate at which to export the object.
* @param z The Z coordinate at which to export the object.
* @param obliterate When <code>true</code>, all blocks of the object are
* placed regardless of what is already there. When <code>false</code>,
* rules are followed and some or all blocks may not be placed,
* depending on what is already there.
*/
public static void renderObject(MinecraftWorld world, Dimension dimension, WPObject object, int x, int y, int z, boolean obliterate) {
final Point3i dim = object.getDimensions();
final Point3i offset = object.getOffset();
final int undergroundMode = object.getAttribute(ATTRIBUTE_UNDERGROUND_MODE);
final int leafDecayMode = object.getAttribute(ATTRIBUTE_LEAF_DECAY_MODE);
final boolean bottomless = dimension.isBottomless();
final int[] replaceBlockIds = object.getAttribute(ATTRIBUTE_REPLACE_WITH_AIR);
final boolean replaceBlocks = replaceBlockIds != null;
final boolean extendFoundation = object.getAttribute(ATTRIBUTE_EXTEND_FOUNDATION);
if ((z + offset.z + dim.z - 1) >= world.getMaxHeight()) {
// Object doesn't fit in the world vertically
return;
}
// System.out.println("Object dimensions: " + dim + ", origin: " + orig);
for (int dx = 0; dx < dim.x; dx++) {
for (int dy = 0; dy < dim.y; dy++) {
final int worldX = x + dx + offset.x;
final int worldY = y + dy + offset.y;
final int terrainHeight = dimension.getIntHeightAt(worldX, worldY);
for (int dz = 0; dz < dim.z; dz++) {
if (object.getMask(dx, dy, dz)) {
final Material objectMaterial = object.getMaterial(dx, dy, dz);
final Material finalMaterial = (replaceBlocks && (objectMaterial.blockType == replaceBlockIds[0]) && (objectMaterial.data == replaceBlockIds[1])) ? Material.AIR : objectMaterial;
final int worldZ = z + dz + offset.z;
if ((bottomless || obliterate) ? (worldZ < 0) : (worldZ < 1)) {
continue;
} else if (obliterate) {
placeBlock(world, worldX, worldY, worldZ, finalMaterial, leafDecayMode);
} else {
final int existingBlockType = world.getBlockTypeAt(worldX, worldY, worldZ);
if (worldZ <= terrainHeight) {
switch(undergroundMode) {
case COLLISION_MODE_ALL:
// Replace every block
placeBlock(world, worldX, worldY, worldZ, finalMaterial, leafDecayMode);
break;
case COLLISION_MODE_SOLID:
// Only replace if object block is solid
if (!objectMaterial.block.veryInsubstantial) {
placeBlock(world, worldX, worldY, worldZ, finalMaterial, leafDecayMode);
}
break;
case COLLISION_MODE_NONE:
// Only replace less solid blocks
if (BLOCKS[existingBlockType].veryInsubstantial) {
placeBlock(world, worldX, worldY, worldZ, finalMaterial, leafDecayMode);
}
break;
}
} else {
// Above ground only replace less solid blocks
if (BLOCKS[existingBlockType].veryInsubstantial) {
placeBlock(world, worldX, worldY, worldZ, finalMaterial, leafDecayMode);
}
}
}
if (extendFoundation && (dz == 0) && (terrainHeight != -1) && (worldZ > terrainHeight) && (!finalMaterial.block.veryInsubstantial)) {
int legZ = worldZ - 1;
while ((legZ >= 0) && world.getMaterialAt(worldX, worldY, legZ).block.veryInsubstantial) {
placeBlock(world, worldX, worldY, legZ, finalMaterial, leafDecayMode);
legZ--;
}
}
}
}
}
}
List<Entity> entities = object.getEntities();
if (entities != null) {
for (Entity entity : entities) {
double[] pos = entity.getPos();
double entityX = x + pos[0] + offset.x, entityY = y + pos[2] + offset.y, entityZ = z + pos[1] + offset.z;
if ((entityZ < 0) || (entityY > (world.getMaxHeight() - 1))) {
if (logger.isTraceEnabled()) {
logger.trace("NOT adding entity " + entity.getId() + " @ " + entityX + "," + entityY + "," + entityZ + " because z coordinate is out of range!");
}
} else {
if (logger.isTraceEnabled()) {
logger.trace("Adding entity " + entity.getId() + " @ " + entityX + "," + entityY + "," + entityZ);
}
// Make sure each entity has a unique ID, otherwise
// Minecraft will see them all as duplicates and remove
// them:
entity.setUUID(UUID.randomUUID());
world.addEntity(entityX, entityY, entityZ, entity);
}
}
}
List<TileEntity> tileEntities = object.getTileEntities();
if (tileEntities != null) {
for (TileEntity tileEntity : tileEntities) {
final int tileEntityX = x + tileEntity.getX() + offset.x, tileEntityY = y + tileEntity.getZ() + offset.y, tileEntityZ = z + tileEntity.getY() + offset.z;
final String entityId = tileEntity.getId();
if ((tileEntityZ < 0) || (tileEntityZ >= world.getMaxHeight())) {
if (logger.isTraceEnabled()) {
logger.trace("NOT adding tile entity " + entityId + " @ " + tileEntityX + "," + tileEntityY + "," + tileEntityZ + " because z coordinate is out of range!");
}
} else {
final int existingBlockType = world.getBlockTypeAt(tileEntityX, tileEntityY, tileEntityZ);
if (!TILE_ENTITY_MAP.containsKey(entityId)) {
if (logger.isTraceEnabled()) {
logger.trace("Adding unknown tile entity " + entityId + " @ " + tileEntityX + "," + tileEntityY + "," + tileEntityZ + " (block type: " + BLOCK_TYPE_NAMES[existingBlockType] + "; not able to detect whether the block type is correct; map may cause errors!)");
}
world.addTileEntity(tileEntityX, tileEntityY, tileEntityZ, tileEntity);
} else if (TILE_ENTITY_MAP.get(entityId).contains(existingBlockType)) {
if (logger.isTraceEnabled()) {
logger.trace("Adding tile entity " + entityId + " @ " + tileEntityX + "," + tileEntityY + "," + tileEntityZ + " (block type: " + BLOCK_TYPE_NAMES[existingBlockType] + ")");
}
world.addTileEntity(tileEntityX, tileEntityY, tileEntityZ, tileEntity);
} else {
// the world limits)
if (logger.isTraceEnabled()) {
logger.trace("NOT adding tile entity " + entityId + " @ " + tileEntityX + "," + tileEntityY + "," + tileEntityZ + " because the block there is not a (or not the same) tile entity: " + BLOCK_TYPE_NAMES[existingBlockType] + "!");
}
}
}
}
}
}
use of org.pepsoft.minecraft.Material in project WorldPainter by Captain-Chaos.
the class GroundCoverLayerExporter method render.
@Override
public void render(Dimension dimension, Tile tile, Chunk chunk) {
if (noiseHeightMap != null) {
noiseHeightMap.setSeed(dimension.getSeed());
}
final int xOffset = (chunk.getxPos() & 7) << 4;
final int zOffset = (chunk.getzPos() & 7) << 4;
final int minY = dimension.isBottomless() ? 0 : 1;
final int maxY = dimension.getMaxHeight() - 1;
final MixedMaterial mixedMaterial = layer.getMaterial();
final int thickness = layer.getThickness(), edgeThickness = Math.abs(thickness) - 2;
final GroundCoverLayer.EdgeShape edgeShape = layer.getEdgeShape();
final boolean taperedEdge = (edgeShape != GroundCoverLayer.EdgeShape.SHEER) && (Math.abs(thickness) > 1);
final int edgeWidth = layer.getEdgeWidth(), edgeWidthPlusOne = edgeWidth + 1, edgeWidthMinusOne = edgeWidth - 1;
final double edgeFactor = edgeThickness / 2.0, edgeOffset = 1.5 + edgeFactor;
final long seed = dimension.getSeed();
final boolean smooth = layer.isSmooth();
for (int x = 0; x < 16; x++) {
final int localX = xOffset + x;
final int worldX = (chunk.getxPos() << 4) + x;
for (int z = 0; z < 16; z++) {
final int localY = zOffset + z;
if (tile.getBitLayerValue(layer, localX, localY)) {
final int terrainheight = tile.getIntHeight(localX, localY);
final int blockBelow = chunk.getBlockType(x, terrainheight, z);
if ((blockBelow != BLK_AIR) && (!Block.BLOCKS[blockBelow].insubstantial)) {
int effectiveThickness = Math.abs(thickness);
final int worldY = (chunk.getzPos() << 4) + z;
if (taperedEdge) {
float distanceToEdge = dimension.getDistanceToEdge(layer, worldX, worldY, edgeWidthPlusOne);
if (distanceToEdge < edgeWidthPlusOne) {
final double normalisedDistance = (distanceToEdge - 1) / edgeWidthMinusOne;
switch(edgeShape) {
case LINEAR:
effectiveThickness = (int) (1.5 + normalisedDistance * edgeThickness);
break;
case SMOOTH:
effectiveThickness = (int) (edgeOffset + -Math.cos(normalisedDistance * Math.PI) * edgeFactor);
break;
case ROUNDED:
double reversedNormalisedDistance = 1 - (distanceToEdge - 0.5) / edgeWidth;
effectiveThickness = (int) (1.5 + Math.sqrt(1 - reversedNormalisedDistance * reversedNormalisedDistance) * edgeThickness);
break;
}
}
}
if (noiseHeightMap != null) {
effectiveThickness += noiseHeightMap.getHeight(worldX, worldY) - noiseOffset;
}
if (thickness > 0) {
for (int dy = 0; dy < effectiveThickness; dy++) {
final int y = terrainheight + dy + 1;
if (y > maxY) {
break;
}
final int existingBlockType = chunk.getBlockType(x, y, z);
final Material material = mixedMaterial.getMaterial(seed, worldX, worldY, y);
if ((material != Material.AIR) && ((!material.block.veryInsubstantial) || (existingBlockType == BLK_AIR) || Block.BLOCKS[existingBlockType].insubstantial)) {
if (smooth && (dy == (effectiveThickness - 1))) {
// Top layer, smooth enabled
int layerHeight = (int) ((dimension.getHeightAt(worldX, worldY) + 0.5f - dimension.getIntHeightAt(worldX, worldY)) / 0.125f);
if (layerHeight > 0) {
layerHeight = Math.max(Math.min(layerHeight, dimension.getBitLayerCount(layer, worldX, worldY, 1) - 2), 0);
}
chunk.setBlockType(x, y, z, material.blockType);
chunk.setDataValue(x, y, z, layerHeight);
} else {
chunk.setMaterial(x, y, z, material);
}
}
}
} else {
for (int dy = 0; dy < effectiveThickness; dy++) {
final int y = terrainheight - dy;
if (y < minY) {
break;
}
int existingBlockType = chunk.getBlockType(x, y, z);
if (existingBlockType != BLK_AIR) {
chunk.setMaterial(x, y, z, mixedMaterial.getMaterial(seed, worldX, worldY, y));
}
}
}
}
}
}
}
}
Aggregations