MixedMaterial implements Serializable, Comparable<MixedMaterial>, Cloneable { public Material getMaterial(long seed, int x, int y, float z) { switch (mode) { case SIMPLE: return simpleMaterial; case NOISE: return materials[random.nextInt(totalCount)]; case BLOBS: double xx = x / Constants.TINY_BLOBS, yy = y / Constants.TINY_BLOBS, zz = z / Constants.TINY_BLOBS; if (seed + 1 != noiseGenerators[0].getSeed()) { for (int i = 0; i < noiseGenerators.length; i++) { noiseGenerators[i].setSeed(seed + i + 1); } } Material material = sortedRows[sortedRows.length - 1].material; for (int i = noiseGenerators.length - 1; i >= 0; i--) { final float rowScale = sortedRows[i].scale * this.scale; if (noiseGenerators[i].getPerlinNoise(xx / rowScale, yy / rowScale, zz / rowScale) >= sortedRows[i].chance) { material = sortedRows[i].material; } } return material; case LAYERED: if (layerNoiseheightMap != null) { if (layerNoiseheightMap.getSeed() != seed) { layerNoiseheightMap.setSeed(seed); } z += layerNoiseheightMap.getValue(x, y, z) - layerNoiseOffset; } if (repeat) { if (layerXSlope != 0.0) { z += layerXSlope * x; } if (layerYSlope != 0.0) { z += layerYSlope * y; } return materials[Math.floorMod(Math.round(z), materials.length)]; } else { final int iZ = Math.round(z); if (iZ < 0) { return materials[0]; } else if (iZ >= materials.length) { return materials[materials.length - 1]; } else { return materials[iZ]; } } default: throw new InternalError(); } } MixedMaterial(final String name, final Row row, final int biome, final Integer colour);  MixedMaterial(final String name, final Row[] rows, final int biome, final Integer colour);  MixedMaterial(final String name, final Row[] rows, final int biome, final Integer colour, final float scale);  MixedMaterial(final String name, final Row[] rows, final int biome, final Integer colour, final NoiseSettings variation, final double layerXSlope, final double layerYSlope, final boolean repeat);   MixedMaterial(final String name, final Row[] rows, final int biome, final Mode mode, final float scale, final Integer colour, final NoiseSettings variation, final double layerXSlope, final double layerYSlope, final boolean repeat); UUID getId(); String getName(); int getBiome(); Mode getMode(); float getScale(); Integer getColour(); NoiseSettings getVariation(); boolean isRepeat(); double getLayerXSlope(); double getLayerYSlope(); BufferedImage getIcon(ColourScheme colourScheme); Material getMaterial(long seed, int x, int y, float z); Material getMaterial(long seed, int x, int y, int z); Material getSingleMaterial(); Row[] getRows(); int getPatternHeight(); @Override int compareTo(MixedMaterial o); @Override String toString(); @Override int hashCode(); @Override boolean equals(Object obj); @Override MixedMaterial clone(); static MixedMaterial create(final Platform platform, final int blockType); static MixedMaterial create(final Platform platform, final Material material); static MixedMaterial create(final String name, final Material material); static V duplicateNewMaterialsWhile(Callable<V> task);  }
@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 + "‰"); }