Added more flowers and more grass types, fixed cross tile render

- Added Clover, Daisy, Dandelion, Geranium, Knapweed, Yellow Pea,
Bluegrass
- Renamed grass herbs and flat flowers
- Cross tile renderer now uses a kostyl that forces face normals to be
oriented vertically
- Refactored flower generation
- Added a coherent error message when a texture could not be found
This commit is contained in:
OLEGSHA 2021-09-22 23:48:38 +03:00
parent eb5aa59941
commit 28b19c8f35
Signed by: OLEGSHA
GPG Key ID: E57A4B08D64AFF7A
41 changed files with 355 additions and 76 deletions

View File

@ -25,6 +25,7 @@ import glm.vec._3.Vec3;
import glm.vec._4.Vec4; import glm.vec._4.Vec4;
import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder; import ru.windcorp.progressia.client.graphics.model.ShapeRenderProgram.VertexBuilder;
import ru.windcorp.progressia.client.graphics.texture.Texture; import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram.WRPVertexBuilder;
import ru.windcorp.progressia.common.world.rels.AbsFace; import ru.windcorp.progressia.common.world.rels.AbsFace;
public class ShapeParts { public class ShapeParts {
@ -40,9 +41,48 @@ public class ShapeParts {
Vec3 width, Vec3 width,
Vec3 height, Vec3 height,
boolean flip boolean flip
) {
return createRectangle(program, texture, colorMultiplier, origin, width, height, flip, null);
}
public static ShapePart createRectangle(
ShapeRenderProgram program,
Texture texture,
Vec4 colorMultiplier,
Vec3 origin,
Vec3 width,
Vec3 height,
boolean flip,
Vec3 forcedNormals
) { ) {
VertexBuilder builder = program.getVertexBuilder(); VertexBuilder builder = program.getVertexBuilder();
if (forcedNormals != null && builder instanceof WRPVertexBuilder) {
((WRPVertexBuilder) builder).addVertex(
origin,
colorMultiplier,
new Vec2(0, 0),
forcedNormals
);
((WRPVertexBuilder) builder).addVertex(
origin.add_(height),
colorMultiplier,
new Vec2(0, 1),
forcedNormals
);
((WRPVertexBuilder) builder).addVertex(
origin.add_(width),
colorMultiplier,
new Vec2(1, 0),
forcedNormals
);
((WRPVertexBuilder) builder).addVertex(
origin.add_(width).add(height),
colorMultiplier,
new Vec2(1, 1),
forcedNormals
);
} else {
builder.addVertex( builder.addVertex(
origin, origin,
colorMultiplier, colorMultiplier,
@ -60,6 +100,7 @@ public class ShapeParts {
colorMultiplier, colorMultiplier,
new Vec2(1, 1) new Vec2(1, 1)
); );
}
ShortBuffer buffer = flip ? ShortBuffer.wrap( ShortBuffer buffer = flip ? ShortBuffer.wrap(
new short[] { new short[] {

View File

@ -28,6 +28,7 @@ import javax.imageio.ImageIO;
import ru.windcorp.progressia.common.resource.Resource; import ru.windcorp.progressia.common.resource.Resource;
import ru.windcorp.progressia.common.util.BinUtil; import ru.windcorp.progressia.common.util.BinUtil;
import ru.windcorp.progressia.common.util.crash.CrashReports;
public class TextureLoader { public class TextureLoader {
@ -99,7 +100,12 @@ public class TextureLoader {
TextureSettings settings TextureSettings settings
) )
throws IOException { throws IOException {
return loadPixels(resource.getInputStream(), settings);
InputStream stream = resource.getInputStream();
if (stream == null) {
throw CrashReports.report(null, "Texture \"%s\" not found", resource.getName());
}
return loadPixels(stream, settings);
} }
private TextureLoader() { private TextureLoader() {

View File

@ -200,6 +200,10 @@ public class WorldRenderProgram extends ShapeRenderProgram {
4 * Float.BYTES + 4 * Float.BYTES +
2 * Float.BYTES); 2 * Float.BYTES);
if (!Float.isNaN(vertices.getFloat(offset + 0 * Float.BYTES))) {
return; // normals are forced
}
vertices.putFloat(offset + 0 * Float.BYTES, normal.x); vertices.putFloat(offset + 0 * Float.BYTES, normal.x);
vertices.putFloat(offset + 1 * Float.BYTES, normal.y); vertices.putFloat(offset + 1 * Float.BYTES, normal.y);
vertices.putFloat(offset + 2 * Float.BYTES, normal.z); vertices.putFloat(offset + 2 * Float.BYTES, normal.z);
@ -212,7 +216,7 @@ public class WorldRenderProgram extends ShapeRenderProgram {
return new WRPVertexBuilder(); return new WRPVertexBuilder();
} }
private static class WRPVertexBuilder implements VertexBuilder { public static class WRPVertexBuilder implements VertexBuilder {
// TODO Throw VertexBuilders out the window and rewrite completely. // TODO Throw VertexBuilders out the window and rewrite completely.
// I want to _extend_ VBs, not re-implement them for children of SRP // I want to _extend_ VBs, not re-implement them for children of SRP
@ -220,11 +224,17 @@ public class WorldRenderProgram extends ShapeRenderProgram {
final Vec3 position; final Vec3 position;
final Vec4 colorMultiplier; final Vec4 colorMultiplier;
final Vec2 textureCoords; final Vec2 textureCoords;
final Vec3 normals;
Vertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords) { Vertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords) {
this(position, colorMultiplier, textureCoords, new Vec3(Float.NaN, Float.NaN, Float.NaN));
}
Vertex(Vec3 position, Vec4 colorMultiplier, Vec2 textureCoords, Vec3 normals) {
this.position = position; this.position = position;
this.colorMultiplier = colorMultiplier; this.colorMultiplier = colorMultiplier;
this.textureCoords = textureCoords; this.textureCoords = textureCoords;
this.normals = normals;
} }
} }
@ -292,6 +302,24 @@ public class WorldRenderProgram extends ShapeRenderProgram {
return this; return this;
} }
public VertexBuilder addVertex(
Vec3 position,
Vec4 colorMultiplier,
Vec2 textureCoords,
Vec3 normals
) {
vertices.add(
new Vertex(
new Vec3(position),
new Vec4(colorMultiplier),
new Vec2(textureCoords),
new Vec3(normals)
)
);
return this;
}
@Override @Override
public ByteBuffer assemble() { public ByteBuffer assemble() {
ByteBuffer result = BufferUtils.createByteBuffer( ByteBuffer result = BufferUtils.createByteBuffer(
@ -309,9 +337,9 @@ public class WorldRenderProgram extends ShapeRenderProgram {
.putFloat(v.colorMultiplier.w) .putFloat(v.colorMultiplier.w)
.putFloat(v.textureCoords.x) .putFloat(v.textureCoords.x)
.putFloat(v.textureCoords.y) .putFloat(v.textureCoords.y)
.putFloat(Float.NaN) .putFloat(v.normals.x)
.putFloat(Float.NaN) .putFloat(v.normals.y)
.putFloat(Float.NaN); .putFloat(v.normals.z);
} }
result.flip(); result.flip();

View File

@ -114,7 +114,8 @@ public class TileRenderCross extends TileRender implements TileOptimizedCustom {
origin, origin,
width, width,
height, height,
false false,
new Vec3(0, 0, 1)
) )
); );
output.accept( output.accept(
@ -125,7 +126,8 @@ public class TileRenderCross extends TileRender implements TileOptimizedCustom {
origin, origin,
width, width,
height, height,
true true,
new Vec3(0, 0, 1)
) )
); );
} }

View File

@ -0,0 +1,147 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import ru.windcorp.progressia.client.graphics.texture.Texture;
import ru.windcorp.progressia.client.world.tile.TileRenderRegistry;
import ru.windcorp.progressia.client.world.tile.TileRenderTransparentSurface;
import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
import ru.windcorp.progressia.server.world.tile.HangingTileLogic;
import ru.windcorp.progressia.server.world.tile.TileLogicRegistry;
public class Flowers {
private static final int HERB_MAX_COUNT = 3;
private static final int TINY_MAX_COUNT = 8;
private static final float TINY_SIZE = 0.5f;
public enum FlowerVariant {
FLAT("Flat"),
TINY("Tiny"),
HERB("Herb");
private final String name;
private FlowerVariant(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static class Flower {
private final String name;
/**
* 1 disables spawning, 0 spawns everywhere
*/
private final float rarity;
private final FlowerVariant[] requestedVariants;
private final Map<FlowerVariant, TileData> tiles = new HashMap<>();
public Flower(String name, float rarity, FlowerVariant... variants) {
Objects.requireNonNull(name, "name");
Objects.requireNonNull(variants, "variants");
this.name = name;
this.rarity = rarity;
this.requestedVariants = variants;
}
public String getName() {
return name;
}
public float getRarity() {
return rarity;
}
public TileData getTile(FlowerVariant variant) {
return tiles.get(variant);
}
public Collection<TileData> getTiles() {
return tiles.values();
}
private void register() {
for (FlowerVariant variant : requestedVariants) {
String fullName = "Flower" + name + variant.getName();
String id = "Test:" + fullName;
TileData tileData = new TileData(id);
tiles.put(variant, tileData);
TileDataRegistry.getInstance().register(tileData);
Texture texture = TileRenderRegistry.getTileTexture(fullName);
TileLogicRegistry logic = TileLogicRegistry.getInstance();
TileRenderRegistry render = TileRenderRegistry.getInstance();
switch (variant) {
case HERB:
logic.register(new HangingTileLogic(id));
render.register(new TileRenderHerb(id, texture, HERB_MAX_COUNT));
break;
case TINY:
logic.register(new HangingTileLogic(id));
render.register(new TileRenderTinyFlower(id, texture, TINY_MAX_COUNT, TINY_SIZE));
break;
case FLAT:
default:
logic.register(new TestTileLogicGrass(id));
render.register(new TileRenderTransparentSurface(id, texture));
break;
}
}
}
}
private final Map<String, Flower> flowersByName = Collections.synchronizedMap(new HashMap<>());
public Flower create(String name, float rarity, FlowerVariant... variants) {
Flower flower = new Flower(name, rarity, variants);
flowersByName.put(name, flower);
return flower;
}
public void registerAllFlowers() {
getFlowers().forEach(Flower::register);
}
public Collection<Flower> getFlowers() {
return flowersByName.values();
}
}

View File

@ -62,6 +62,7 @@ import ru.windcorp.progressia.server.world.context.ServerTileStackContext;
import ru.windcorp.progressia.server.world.entity.*; import ru.windcorp.progressia.server.world.entity.*;
import ru.windcorp.progressia.server.world.generation.planet.PlanetGravityModel; import ru.windcorp.progressia.server.world.generation.planet.PlanetGravityModel;
import ru.windcorp.progressia.server.world.tile.*; import ru.windcorp.progressia.server.world.tile.*;
import ru.windcorp.progressia.test.Flowers.FlowerVariant;
import ru.windcorp.progressia.test.Rocks.RockType; import ru.windcorp.progressia.test.Rocks.RockType;
import ru.windcorp.progressia.test.gen.TestGravityModel; import ru.windcorp.progressia.test.gen.TestGravityModel;
@ -75,6 +76,7 @@ public class TestContent {
public static final List<TileData> PLACEABLE_TILES = new ArrayList<>(); public static final List<TileData> PLACEABLE_TILES = new ArrayList<>();
public static final Rocks ROCKS = new Rocks(); public static final Rocks ROCKS = new Rocks();
public static final Flowers FLOWERS = new Flowers();
public static void registerContent() { public static void registerContent() {
registerWorldContent(); registerWorldContent();
@ -184,14 +186,7 @@ public class TestContent {
register(new TestTileLogicGrass(id)); register(new TestTileLogicGrass(id));
}); });
Arrays.asList( registerFlowers();
"Yellow",
"White",
"Purple",
"Blue"
).forEach(color -> {
registerSimplestTransparentTile(color + "Flowers");
});
registerSimplestTransparentTile("Stones"); registerSimplestTransparentTile("Stones");
@ -216,21 +211,12 @@ public class TestContent {
registerSimplestOpaqueTile("TilesLarge"); registerSimplestOpaqueTile("TilesLarge");
registerSimplestOpaqueTile("TilesSmall"); registerSimplestOpaqueTile("TilesSmall");
registerHerb("LowGrass", 6); registerHerb("GrassMeadow0", 6);
registerHerb("MediumGrass", 6); registerHerb("GrassMeadow1", 6);
registerHerb("TallGrass", 6); registerHerb("GrassMeadow2", 6);
registerHerb("GrassBluegrass0", 6);
Arrays.asList( registerHerb("GrassBluegrass1", 6);
"Dandelion", registerHerb("GrassBluegrass2", 6);
"Lavander"
).forEach(variant -> {
String fullName = "Tiny" + variant + "Flowers";
String id = "Test:" + fullName;
register(new TileData(id));
register(new TileRenderTinyFlower(id, getTileTexture(fullName), 8, 0.5f));
register(new HangingTileLogic(id));
});
registerHerb("Bush", 1); registerHerb("Bush", 1);
registerHerb("Fern", 3); registerHerb("Fern", 3);
@ -240,6 +226,21 @@ public class TestContent {
PLACEABLE_TILES.sort(Comparator.comparing(TileData::getId)); PLACEABLE_TILES.sort(Comparator.comparing(TileData::getId));
} }
private static void registerFlowers() {
final float common = 0.8f;
FLOWERS.create("Clover", common, FlowerVariant.HERB, FlowerVariant.TINY, FlowerVariant.FLAT);
FLOWERS.create("Dandelion", common, FlowerVariant.TINY, FlowerVariant.FLAT);
FLOWERS.create("Geranium", common, FlowerVariant.TINY, FlowerVariant.FLAT);
FLOWERS.create("Knapweed", common, FlowerVariant.TINY, FlowerVariant.FLAT);
FLOWERS.create("YellowPea", common, FlowerVariant.TINY, FlowerVariant.FLAT);
FLOWERS.create("Daisy", common, FlowerVariant.TINY, FlowerVariant.FLAT);
FLOWERS.create("Lavander", common, FlowerVariant.TINY, FlowerVariant.FLAT);
FLOWERS.registerAllFlowers();
}
private static void registerSimplestBlock(String name) { private static void registerSimplestBlock(String name) {
String id = "Test:" + name; String id = "Test:" + name;
register(new BlockData(id)); register(new BlockData(id));

View File

@ -219,6 +219,10 @@ public class Fields {
return tweak(f, 1, -1, 1); return tweak(f, 1, -1, 1);
} }
public static Field rarify(Field f, float rarity) {
return (x, y) -> Math.max((f.compute(x, y) - rarity) / (1 - rarity), 0);
}
public static Field octaves(Field f, double scaleFactor, double amplitudeFactor, int octaves) { public static Field octaves(Field f, double scaleFactor, double amplitudeFactor, int octaves) {
return (x, y) -> { return (x, y) -> {
double result = 0; double result = 0;

View File

@ -26,6 +26,7 @@ import java.util.function.Function;
import ru.windcorp.progressia.common.Units; import ru.windcorp.progressia.common.Units;
import ru.windcorp.progressia.common.util.noise.discrete.WorleyProceduralNoise; import ru.windcorp.progressia.common.util.noise.discrete.WorleyProceduralNoise;
import ru.windcorp.progressia.common.world.Coordinates; import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.generation.WorldGenerator; import ru.windcorp.progressia.server.world.generation.WorldGenerator;
import ru.windcorp.progressia.server.world.generation.planet.Planet; import ru.windcorp.progressia.server.world.generation.planet.Planet;
@ -125,19 +126,16 @@ public class TestGenerationConfig {
) )
); );
Function<String, SurfaceFloatField> floweriness = flowerName -> fields.register( Function<AbsFace, Field> floweriness = f -> multiply(
"Test:Flower" + flowerName, amplify(withMin(squash(scale(octaves(fields.primitive(), 2, 3), 100), 5), 0), 2),
f -> multiply(
selectPositive(squash(scale(octaves(fields.primitive(), 2, 3), 100), 2), 1, 0.5),
tweak(fields.get("Test:Forest", f), 1, -1, 1.1), tweak(fields.get("Test:Forest", f), 1, -1, 1.1),
anti(squash(fields.get("Test:Cliff", f), 10)) anti(squash(fields.get("Test:Cliff", f), 10))
)
); );
features.add(new TestBushFeature("Test:BushFeature", forestiness)); features.add(new TestBushFeature("Test:BushFeature", forestiness));
features.add(new TestTreeFeature("Test:TreeFeature", forestiness)); features.add(new TestTreeFeature("Test:TreeFeature", forestiness));
features.add(new TestGrassFeature("Test:GrassFeature", grassiness)); features.add(new TestGrassFeature("Test:GrassFeature", grassiness));
features.add(new TestFlowerFeature("Test:FlowerFeature", floweriness)); features.add(new TestFlowerFeature("Test:FlowerFeature", TestContent.FLOWERS, floweriness, fields));
} }
} }

View File

@ -17,35 +17,73 @@
*/ */
package ru.windcorp.progressia.test.gen.feature; package ru.windcorp.progressia.test.gen.feature;
import java.util.ArrayList;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.common.world.rels.RelFace; import ru.windcorp.progressia.common.world.rels.RelFace;
import ru.windcorp.progressia.common.world.tile.TileData; import ru.windcorp.progressia.common.world.tile.TileData;
import ru.windcorp.progressia.common.world.tile.TileDataRegistry;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField; import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceTopLayerFeature; import ru.windcorp.progressia.server.world.generation.surface.SurfaceTopLayerFeature;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext; import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
import ru.windcorp.progressia.test.Flowers;
import ru.windcorp.progressia.test.Flowers.Flower;
import ru.windcorp.progressia.test.Flowers.FlowerVariant;
import ru.windcorp.progressia.test.TestContent; import ru.windcorp.progressia.test.TestContent;
import ru.windcorp.progressia.test.gen.Fields;
import ru.windcorp.progressia.test.gen.Fields.Field;
public class TestFlowerFeature extends SurfaceTopLayerFeature { public class TestFlowerFeature extends SurfaceTopLayerFeature {
private static class FlowerGenerator { private static class FlowerGenerator {
private final TileData tile;
private final TileData[] variants;
private final SurfaceFloatField floweriness; private final SurfaceFloatField floweriness;
public FlowerGenerator(TileData tile, Function<String, SurfaceFloatField> flowerinessGenerator) { public FlowerGenerator(Flower flower, Function<AbsFace, Field> flowerinessGenerator, Fields fields) {
this.tile = tile; this.floweriness = fields.register(
this.floweriness = flowerinessGenerator.apply(tile.getName()); "Test:Flower" + flower.getName(),
f -> Fields.rarify(flowerinessGenerator.apply(f), flower.getRarity())
);
List<TileData> tiles = new ArrayList<>();
for (FlowerVariant variant : FlowerVariant.values()) {
TileData tile = flower.getTile(variant);
if (tile == null) {
continue;
}
tiles.add(tile);
}
this.variants = tiles.toArray(new TileData[tiles.size()]);
} }
public void generate(SurfaceBlockContext context) { public void generate(SurfaceBlockContext context) {
if (context.getRandom().nextDouble() < floweriness.get(context)) { float floweriness = this.floweriness.get(context);
context.addTile(RelFace.UP, tile);
if (floweriness <= 0) {
return;
} }
float random = context.getRandom().nextFloat();
int variant = (int) Math.floor((random + floweriness - 1) * variants.length);
if (variant < 0) {
return;
} else if (variant >= variants.length) {
// Screw doing float math properly, just clamp it
variant = variants.length - 1;
} }
context.addTile(RelFace.UP, variants[variant]);
}
} }
private final Set<String> soilWhitelist; private final Set<String> soilWhitelist;
@ -58,12 +96,11 @@ public class TestFlowerFeature extends SurfaceTopLayerFeature {
private final FlowerGenerator[] flowers; private final FlowerGenerator[] flowers;
public TestFlowerFeature(String id, Function<String, SurfaceFloatField> flowerinessGenerator) { public TestFlowerFeature(String id, Flowers flowers, Function<AbsFace, Field> flowerinessGenerator, Fields fields) {
super(id); super(id);
this.flowers = TileDataRegistry.getInstance().values().stream() this.flowers = flowers.getFlowers().stream()
.filter(tile -> tile.getName().endsWith("Flowers")) .map(flower -> new FlowerGenerator(flower, flowerinessGenerator, fields))
.map(tile -> new FlowerGenerator(tile, flowerinessGenerator))
.toArray(FlowerGenerator[]::new); .toArray(FlowerGenerator[]::new);
} }

View File

@ -19,6 +19,7 @@ package ru.windcorp.progressia.test.gen.feature;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
@ -58,11 +59,25 @@ public class TestGrassFeature extends SurfaceTopLayerFeature {
flatGrasses.put(0.05f, 0.1f, TileDataRegistry.getInstance().get("Test:GrassThreads")); flatGrasses.put(0.05f, 0.1f, TileDataRegistry.getInstance().get("Test:GrassThreads"));
} }
private final FloatRangeMap<TileData> herbGrasses = new ArrayFloatRangeMap<>(); private static final Function<SurfaceBlockContext, TileData> randomPicker(String commonId, String rareId) {
TileData common = TileDataRegistry.getInstance().get(commonId);
TileData rare = TileDataRegistry.getInstance().get(rareId);
final float rareChance = 0.2f;
return context -> {
if (context.getRandom().nextFloat() < rareChance) {
return rare;
} else {
return common;
}
};
}
private final FloatRangeMap<Function<SurfaceBlockContext, TileData>> herbGrasses = new ArrayFloatRangeMap<>();
{ {
herbGrasses.put(0.6f, 1, TileDataRegistry.getInstance().get("Test:TallGrass")); herbGrasses.put(0.6f, 1, randomPicker("Test:GrassMeadow2", "Test:GrassBluegrass2"));
herbGrasses.put(0.4f, 0.6f, TileDataRegistry.getInstance().get("Test:MediumGrass")); herbGrasses.put(0.4f, 0.6f, randomPicker("Test:GrassMeadow1", "Test:GrassBluegrass1"));
herbGrasses.put(0.1f, 0.4f, TileDataRegistry.getInstance().get("Test:LowGrass")); herbGrasses.put(0.1f, 0.4f, randomPicker("Test:GrassMeadow0", "Test:GrassBluegrass0"));
} }
private final List<TileData> scatter = ImmutableList.of( private final List<TileData> scatter = ImmutableList.of(
@ -134,9 +149,9 @@ public class TestGrassFeature extends SurfaceTopLayerFeature {
} }
if (context.getRandom().nextDouble() < grassiness) { if (context.getRandom().nextDouble() < grassiness) {
TileData herbGrass = herbGrasses.get((float) grassiness); Function<SurfaceBlockContext, TileData> herbGrass = herbGrasses.get((float) grassiness);
if (herbGrass != null) { if (herbGrass != null) {
context.addTile(RelFace.UP, herbGrass); context.addTile(RelFace.UP, herbGrass.apply(context));
} }
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 481 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 977 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 458 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 B

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB