/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package org.pepsoft.worldpainter.layers.plants; import org.pepsoft.minecraft.Constants; import org.pepsoft.minecraft.Material; import org.pepsoft.worldpainter.Dimension; import org.pepsoft.worldpainter.Tile; import org.pepsoft.worldpainter.exporting.Fixup; import org.pepsoft.worldpainter.exporting.IncidentalLayerExporter; import org.pepsoft.worldpainter.exporting.MinecraftWorld; import org.pepsoft.worldpainter.exporting.SecondPassLayerExporter; import org.pepsoft.worldpainter.layers.bo2.Bo2ObjectProvider; import org.pepsoft.worldpainter.layers.exporters.WPObjectExporter; import javax.vecmath.Point3i; import java.awt.*; import java.util.List; import java.util.Random; import static org.pepsoft.minecraft.Block.BLOCKS; import static org.pepsoft.worldpainter.Constants.TILE_SIZE; import static org.pepsoft.worldpainter.Constants.TILE_SIZE_BITS; /** * * @author pepijn */ public class PlantLayerExporter extends WPObjectExporter<PlantLayer> implements SecondPassLayerExporter, IncidentalLayerExporter { public PlantLayerExporter(PlantLayer layer) { super(layer); } @Override public List<Fixup> render(Dimension dimension, Rectangle area, Rectangle exportedArea, MinecraftWorld minecraftWorld) { final long seed = dimension.getSeed(); final int tileX1 = exportedArea.x >> TILE_SIZE_BITS, tileX2 = (exportedArea.x + exportedArea.width - 1) >> TILE_SIZE_BITS; final int tileY1 = exportedArea.y >> TILE_SIZE_BITS, tileY2 = (exportedArea.y + exportedArea.height - 1) >> TILE_SIZE_BITS; final int maxY = minecraftWorld.getMaxHeight() - 1; final boolean generateTilledDirt = layer.isGenerateTilledDirt(); final boolean blockRulesEnforced = ! "false".equalsIgnoreCase(System.getProperty("org.pepsoft.worldpainter.enforceBlockRules")); final Bo2ObjectProvider objectProvider = layer.getObjectProvider(); for (int tileX = tileX1; tileX <= tileX2; tileX++) { for (int tileY = tileY1; tileY <= tileY2; tileY++) { final Tile tile = dimension.getTile(tileX, tileY); if ((tile == null) || (! tile.hasLayer(layer))) { // Tile doesn't exist, or it doesn't have the layer continue; } final long tileSeed = (long) tileX << 32 ^ tileY ^ seed; objectProvider.setSeed(tileSeed); for (int x = 0; x < TILE_SIZE; x++) { for (int y = 0; y < TILE_SIZE; y++) { if (tile.getBitLayerValue(layer, x, y)) { // Possibly place a plant final int height = tile.getIntHeight(x, y); if (height < maxY) { final int worldX = (tileX << TILE_SIZE_BITS) | x, worldY = (tileY << TILE_SIZE_BITS) | y; final Plant plant = (Plant) objectProvider.getObject(); if (plant.getCategory() == Plant.Category.WATER_PLANTS) { if ((! blockRulesEnforced) || plant.isValidFoundation(minecraftWorld, worldX, worldY, height)) { possiblyRenderWaterPlant(minecraftWorld, dimension, plant, worldX, worldY, height + 1); } } else { if (tile.getIntHeight(x, y) >= tile.getWaterLevel(x, y)) { if (! blockRulesEnforced) { renderObject(minecraftWorld, dimension, plant, worldX, worldY, height + 1, false); if (generateTilledDirt && (plant.getCategory() == Plant.Category.CROPS) && ((minecraftWorld.getBlockTypeAt(worldX, worldY, height) == Constants.BLK_GRASS) || (minecraftWorld.getBlockTypeAt(worldX, worldY, height) == Constants.BLK_DIRT))) { minecraftWorld.setMaterialAt(worldX, worldY, height, TILLED_DIRT); } } else { if (plant.isValidFoundation(minecraftWorld, worldX, worldY, height)) { renderObject(minecraftWorld, dimension, plant, worldX, worldY, height + 1, false); } else if (generateTilledDirt && (plant.getCategory() == Plant.Category.CROPS) && ((minecraftWorld.getBlockTypeAt(worldX, worldY, height) == Constants.BLK_GRASS) || (minecraftWorld.getBlockTypeAt(worldX, worldY, height) == Constants.BLK_DIRT))) { minecraftWorld.setMaterialAt(worldX, worldY, height, TILLED_DIRT); renderObject(minecraftWorld, dimension, plant, worldX, worldY, height + 1, false); } } } } } } } } } } return null; } @Override public Fixup apply(Dimension dimension, Point3i location, int intensity, Rectangle exportedArea, MinecraftWorld minecraftWorld) { final Random random = incidentalRandomRef.get(); final long seed = dimension.getSeed() ^ ((long) location.x << 40) ^ ((long) location.y << 20) ^ (location.z); random.setSeed(seed); if ((intensity >= 100) || ((intensity > 0) && (random.nextInt(100) < intensity))) { // Place plant final Bo2ObjectProvider objectProvider = layer.getObjectProvider(); objectProvider.setSeed(seed); final Plant plant = (Plant) objectProvider.getObject(); final int existingBlockType = minecraftWorld.getBlockTypeAt(location.x, location.y, location.z); if ((location.z < (minecraftWorld.getMaxHeight() - 1)) && ((plant.getCategory() == Plant.Category.WATER_PLANTS) ? ((existingBlockType == Constants.BLK_WATER) || (existingBlockType == Constants.BLK_STATIONARY_WATER)) : (existingBlockType == Constants.BLK_AIR))) { if (plant.isValidFoundation(minecraftWorld, location.x, location.y, location.z - 1)) { if (plant.getCategory() == Plant.Category.WATER_PLANTS) { possiblyRenderWaterPlant(minecraftWorld, dimension, plant, location.x, location.y, location.z + 1); } else { renderObject(minecraftWorld, dimension, plant, location.x, location.y, location.z, false); } } else if (layer.isGenerateTilledDirt() && (plant.getCategory() == Plant.Category.CROPS) && ((minecraftWorld.getBlockTypeAt(location.x, location.y, location.z - 1) == Constants.BLK_GRASS) || (minecraftWorld.getBlockTypeAt(location.x, location.y, location.z - 1) == Constants.BLK_DIRT))) { minecraftWorld.setMaterialAt(location.x, location.y, location.z - 1, TILLED_DIRT); renderObject(minecraftWorld, dimension, plant, location.x, location.y, location.z, false); } } } return null; } private void possiblyRenderWaterPlant(MinecraftWorld world, Dimension dimension, Plant plant, int x, int y, int z) { final int maxHeight = world.getMaxHeight(); int existingBlockType; do { z++; existingBlockType = world.getBlockTypeAt(x, y, z); } while ((z < maxHeight) && ((existingBlockType == Constants.BLK_STATIONARY_WATER) || (existingBlockType == Constants.BLK_WATER))); if ((z < maxHeight) && BLOCKS[existingBlockType].veryInsubstantial && (! ((existingBlockType == Constants.BLK_LAVA) || (existingBlockType == Constants.BLK_STATIONARY_LAVA)))) { renderObject(world, dimension, plant, x, y, z, false); } } private final ThreadLocal<Random> incidentalRandomRef = new ThreadLocal<Random>() { @Override protected Random initialValue() { return new Random(); } }; private static final Material TILLED_DIRT = Material.get(Constants.BLK_TILLED_DIRT, 4); }