This commit is contained in:
Brian Neumann-Fopiano
2026-02-20 17:53:11 -05:00
parent afc5f67bc2
commit 3964185a81
30 changed files with 1433 additions and 1473 deletions

2
.gitignore vendored
View File

@@ -11,3 +11,5 @@ libs/
collection/
/core/src/main/java/art/arcane/iris/util/uniques/
DataPackExamples/

Binary file not shown.

View File

@@ -257,7 +257,6 @@ public class IrisSettings {
public boolean preventLeafDecay = true;
public boolean useMulticore = false;
public boolean useMulticoreMantle = false;
public boolean offsetNoiseTypes = false;
public boolean earlyCustomBlocks = false;
}

View File

@@ -20,6 +20,7 @@ package art.arcane.iris.core;
import art.arcane.iris.Iris;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.core.loader.ResourceLoader;
import art.arcane.iris.core.nms.INMS;
import art.arcane.iris.core.nms.datapack.DataVersion;
import art.arcane.iris.core.nms.datapack.IDataFixer;
@@ -142,27 +143,156 @@ public class ServerConfigurator {
return;
}
File source = Iris.instance.getDataFolder("datapacks");
source.mkdirs();
ExternalDataPackPipeline.syncPinnedDatapacks(source);
int removedLegacyCopies = ExternalDataPackPipeline.removeLegacyWorldDatapackCopies(source, folders);
ExternalDataPackPipeline.ImportSummary summary = ExternalDataPackPipeline.importDatapackStructures(source);
if (removedLegacyCopies > 0) {
Iris.info("Removed " + removedLegacyCopies + " legacy external datapack world copies.");
KList<ExternalDataPackPipeline.DatapackRequest> requests = collectExternalDatapackRequests();
KMap<String, KList<File>> worldDatapackFoldersByPack = collectWorldDatapackFoldersByPack(folders);
ExternalDataPackPipeline.PipelineSummary summary = ExternalDataPackPipeline.processDatapacks(requests, worldDatapackFoldersByPack);
if (summary.getLegacyDownloadRemovals() > 0) {
Iris.info("Removed " + summary.getLegacyDownloadRemovals() + " legacy global datapack downloads.");
}
if (summary.getSources() > 0) {
Iris.info("External datapack structure import: sources=" + summary.getSources()
+ ", cached=" + summary.getCachedSources()
+ ", scanned=" + summary.getNbtScanned()
+ ", converted=" + summary.getConverted()
+ ", failed=" + summary.getFailed()
+ ", skipped=" + summary.getSkipped()
+ ", entitiesIgnored=" + summary.getEntitiesIgnored()
+ ", blockEntities=" + summary.getBlockEntities());
if (summary.getLegacyWorldCopyRemovals() > 0) {
Iris.info("Removed " + summary.getLegacyWorldCopyRemovals() + " legacy managed world datapack copies.");
}
if (summary.getSources() > 0 || summary.getConverted() > 0) {
Iris.info("External datapack world install is disabled; only structure template import is applied.");
if (summary.getRequests() > 0 || summary.getImportedSources() > 0 || summary.getWorldDatapacksInstalled() > 0) {
Iris.info("External datapack sync/import/install: requests=" + summary.getRequests()
+ ", synced=" + summary.getSyncedRequests()
+ ", restored=" + summary.getRestoredRequests()
+ ", importedSources=" + summary.getImportedSources()
+ ", cachedSources=" + summary.getCachedSources()
+ ", converted=" + summary.getConvertedStructures()
+ ", failedConversions=" + summary.getFailedConversions()
+ ", worldDatapacks=" + summary.getWorldDatapacksInstalled()
+ ", worldAssets=" + summary.getWorldAssetsInstalled()
+ ", optionalFailures=" + summary.getOptionalFailures()
+ ", requiredFailures=" + summary.getRequiredFailures());
}
if (summary.getRequiredFailures() > 0) {
throw new IllegalStateException("Required external datapack setup failed for " + summary.getRequiredFailures() + " request(s).");
}
}
private static KList<ExternalDataPackPipeline.DatapackRequest> collectExternalDatapackRequests() {
KMap<String, ExternalDataPackPipeline.DatapackRequest> deduplicated = new KMap<>();
try (Stream<IrisData> stream = allPacks()) {
stream.forEach(data -> {
ResourceLoader<IrisDimension> loader = data.getDimensionLoader();
if (loader == null) {
return;
}
KList<IrisDimension> dimensions = loader.loadAll(loader.getPossibleKeys());
for (IrisDimension dimension : dimensions) {
if (dimension == null || dimension.getExternalDatapacks() == null || dimension.getExternalDatapacks().isEmpty()) {
continue;
}
String targetPack = sanitizePackName(dimension.getLoadKey());
if (targetPack.isBlank()) {
targetPack = sanitizePackName(data.getDataFolder().getName());
}
String environment = ExternalDataPackPipeline.normalizeEnvironmentValue(dimension.getEnvironment() == null ? null : dimension.getEnvironment().name());
for (IrisExternalDatapack externalDatapack : dimension.getExternalDatapacks()) {
if (externalDatapack == null || !externalDatapack.isEnabled()) {
continue;
}
String url = externalDatapack.getUrl() == null ? "" : externalDatapack.getUrl().trim();
if (url.isBlank()) {
continue;
}
String requestId = externalDatapack.getId() == null ? "" : externalDatapack.getId().trim();
if (requestId.isBlank()) {
requestId = url;
}
IrisExternalDatapackReplaceTargets replaceTargets = externalDatapack.getReplaceTargets();
ExternalDataPackPipeline.DatapackRequest request = new ExternalDataPackPipeline.DatapackRequest(
requestId,
url,
targetPack,
environment,
externalDatapack.isRequired(),
externalDatapack.isReplaceVanilla(),
replaceTargets
);
String dedupeKey = request.getDedupeKey();
ExternalDataPackPipeline.DatapackRequest existing = deduplicated.get(dedupeKey);
if (existing == null) {
deduplicated.put(dedupeKey, request);
continue;
}
deduplicated.put(dedupeKey, existing.merge(request));
}
}
});
}
return new KList<>(deduplicated.v());
}
private static KMap<String, KList<File>> collectWorldDatapackFoldersByPack(KList<File> fallbackFolders) {
KMap<String, KList<File>> foldersByPack = new KMap<>();
KMap<String, String> mappedWorlds = IrisWorlds.get().getWorlds();
for (String worldName : mappedWorlds.k()) {
String packName = sanitizePackName(mappedWorlds.get(worldName));
if (packName.isBlank()) {
continue;
}
File datapacksFolder = new File(Bukkit.getWorldContainer(), worldName + File.separator + "datapacks");
addWorldDatapackFolder(foldersByPack, packName, datapacksFolder);
}
for (org.bukkit.World world : Bukkit.getWorlds()) {
String worldName = world.getName();
String mappedPack = mappedWorlds.get(worldName);
String packName = sanitizePackName(mappedPack);
if (packName.isBlank()) {
packName = sanitizePackName(IrisSettings.get().getGenerator().getDefaultWorldType());
}
if (packName.isBlank()) {
continue;
}
File datapacksFolder = new File(world.getWorldFolder(), "datapacks");
addWorldDatapackFolder(foldersByPack, packName, datapacksFolder);
}
String defaultPack = sanitizePackName(IrisSettings.get().getGenerator().getDefaultWorldType());
if (!defaultPack.isBlank()) {
for (File folder : fallbackFolders) {
addWorldDatapackFolder(foldersByPack, defaultPack, folder);
}
}
return foldersByPack;
}
private static void addWorldDatapackFolder(KMap<String, KList<File>> foldersByPack, String packName, File folder) {
if (folder == null || packName == null || packName.isBlank()) {
return;
}
KList<File> folders = foldersByPack.computeIfAbsent(packName, k -> new KList<>());
if (!folders.contains(folder)) {
folders.add(folder);
}
}
private static String sanitizePackName(String value) {
if (value == null) {
return "";
}
String sanitized = value.trim().toLowerCase().replace("\\", "/");
sanitized = sanitized.replaceAll("[^a-z0-9_\\-./]", "_");
sanitized = sanitized.replaceAll("/+", "/");
sanitized = sanitized.replaceAll("^/+", "");
sanitized = sanitized.replaceAll("/+$", "");
if (sanitized.contains("..")) {
sanitized = sanitized.replace("..", "_");
}
return sanitized.replace("/", "_");
}
private static boolean verifyDataPacksPost(boolean allowRestarting) {

View File

@@ -114,22 +114,4 @@ public class CommandEdit implements DirectorExecutor {
}
}
@Director(description = "Edit the cave file you specified", aliases = {"c"}, origin = DirectorOrigin.PLAYER)
public void cave(@Param(contextual = false, description = "The cave to edit") IrisCave cave) {
if (noStudio()) {
return;
}
try {
if (cave == null || cave.getLoadFile() == null) {
sender().sendMessage(C.GOLD + "Cannot find the file; Perhaps it was not loaded directly from a file?");
return;
}
Desktop.getDesktop().open(cave.getLoadFile());
sender().sendMessage(C.GREEN + "Opening " + cave.getTypeName() + " " + cave.getLoadFile().getName().split("\\Q.\\E")[0] + " in VSCode! ");
} catch (Throwable e) {
Iris.reportError(e);
sender().sendMessage(C.RED + "Cant find the file. Or registrant does not exist");
}
}
}

View File

@@ -74,8 +74,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
private ResourceLoader<IrisMatterObject> matterLoader;
private ResourceLoader<IrisImage> imageLoader;
private ResourceLoader<IrisScript> scriptLoader;
private ResourceLoader<IrisCave> caveLoader;
private ResourceLoader<IrisRavine> ravineLoader;
private ResourceLoader<IrisMatterObject> matterObjectLoader;
private KMap<String, KList<String>> possibleSnippets;
private Gson gson;
@@ -158,10 +156,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
return loadAny(IrisScript.class, key, nearest);
}
public static IrisRavine loadAnyRavine(String key, @Nullable IrisData nearest) {
return loadAny(IrisRavine.class, key, nearest);
}
public static IrisRegion loadAnyRegion(String key, @Nullable IrisData nearest) {
return loadAny(IrisRegion.class, key, nearest);
}
@@ -170,10 +164,6 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
return loadAny(IrisMarker.class, key, nearest);
}
public static IrisCave loadAnyCave(String key, @Nullable IrisData nearest) {
return loadAny(IrisCave.class, key, nearest);
}
public static IrisImage loadAnyImage(String key, @Nullable IrisData nearest) {
return loadAny(IrisImage.class, key, nearest);
}
@@ -352,9 +342,7 @@ public class IrisData implements ExclusionStrategy, TypeAdapterFactory {
this.modLoader = registerLoader(IrisMod.class);
this.dimensionLoader = registerLoader(IrisDimension.class);
this.generatorLoader = registerLoader(IrisGenerator.class);
this.caveLoader = registerLoader(IrisCave.class);
this.markerLoader = registerLoader(IrisMarker.class);
this.ravineLoader = registerLoader(IrisRavine.class);
this.blockLoader = registerLoader(IrisBlockData.class);
this.expressionLoader = registerLoader(IrisExpression.class);
this.objectLoader = registerLoader(IrisObject.class);

View File

@@ -119,7 +119,6 @@ public class IrisComplex implements DataProvider {
.forEach(this::registerGenerators));
}
generatorBounds = buildGeneratorBounds(engine);
boolean legacy = engine.getDimension().isLegacyRarity();
KList<IrisShapedGeneratorStyle> overlayNoise = engine.getDimension().getOverlayNoise();
overlayStream = overlayNoise.isEmpty()
? ProceduralStream.ofDouble((x, z) -> 0.0D).waste("Overlay Stream")
@@ -143,7 +142,7 @@ public class IrisComplex implements DataProvider {
ProceduralStream.of((x, z) -> focusRegion,
Interpolated.of(a -> 0D, a -> focusRegion))
: regionStyleStream
.selectRarity(data.getRegionLoader().loadAll(engine.getDimension().getRegions()), legacy)
.selectRarity(data.getRegionLoader().loadAll(engine.getDimension().getRegions()))
.cache2D("regionStream", engine, cacheSize).waste("Region Stream");
regionIDStream = regionIdentityStream.convertCached((i) -> new UUID(Double.doubleToLongBits(i),
String.valueOf(i * 38445).hashCode() * 3245556666L)).waste("Region ID Stream");
@@ -152,7 +151,7 @@ public class IrisComplex implements DataProvider {
-> engine.getDimension().getCaveBiomeStyle().create(rng.nextParallelRNG(InferredType.CAVE.ordinal()), getData()).stream()
.zoom(engine.getDimension().getBiomeZoom())
.zoom(r.getCaveBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getCaveBiomes()), legacy)
.selectRarity(data.getBiomeLoader().loadAll(r.getCaveBiomes()))
.onNull(emptyBiome)
).convertAware2D(ProceduralStream::get).cache2D("caveBiomeStream", engine, cacheSize).waste("Cave Biome Stream");
inferredStreams.put(InferredType.CAVE, caveBiomeStream);
@@ -162,7 +161,7 @@ public class IrisComplex implements DataProvider {
.zoom(engine.getDimension().getBiomeZoom())
.zoom(engine.getDimension().getLandZoom())
.zoom(r.getLandBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getLandBiomes(), (t) -> t.setInferredType(InferredType.LAND)), legacy)
.selectRarity(data.getBiomeLoader().loadAll(r.getLandBiomes(), (t) -> t.setInferredType(InferredType.LAND)))
).convertAware2D(ProceduralStream::get)
.cache2D("landBiomeStream", engine, cacheSize).waste("Land Biome Stream");
inferredStreams.put(InferredType.LAND, landBiomeStream);
@@ -172,7 +171,7 @@ public class IrisComplex implements DataProvider {
.zoom(engine.getDimension().getBiomeZoom())
.zoom(engine.getDimension().getSeaZoom())
.zoom(r.getSeaBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getSeaBiomes(), (t) -> t.setInferredType(InferredType.SEA)), legacy)
.selectRarity(data.getBiomeLoader().loadAll(r.getSeaBiomes(), (t) -> t.setInferredType(InferredType.SEA)))
).convertAware2D(ProceduralStream::get)
.cache2D("seaBiomeStream", engine, cacheSize).waste("Sea Biome Stream");
inferredStreams.put(InferredType.SEA, seaBiomeStream);
@@ -181,7 +180,7 @@ public class IrisComplex implements DataProvider {
-> engine.getDimension().getShoreBiomeStyle().create(rng.nextParallelRNG(InferredType.SHORE.ordinal()), getData()).stream()
.zoom(engine.getDimension().getBiomeZoom())
.zoom(r.getShoreBiomeZoom())
.selectRarity(data.getBiomeLoader().loadAll(r.getShoreBiomes(), (t) -> t.setInferredType(InferredType.SHORE)), legacy)
.selectRarity(data.getBiomeLoader().loadAll(r.getShoreBiomes(), (t) -> t.setInferredType(InferredType.SHORE)))
).convertAware2D(ProceduralStream::get).cache2D("shoreBiomeStream", engine, cacheSize).waste("Shore Biome Stream");
inferredStreams.put(InferredType.SHORE, shoreBiomeStream);
bridgeStream = focusBiome != null ? ProceduralStream.of((x, z) -> focusBiome.getInferredType(),

View File

@@ -41,6 +41,7 @@ import art.arcane.volmlib.util.mantle.runtime.MantleDataAdapter;
import art.arcane.volmlib.util.mantle.runtime.MantleHooks;
import art.arcane.volmlib.util.mantle.runtime.TectonicPlate;
import art.arcane.volmlib.util.mantle.flag.MantleFlag;
import art.arcane.volmlib.util.mantle.flag.ReservedFlag;
import art.arcane.volmlib.util.scheduling.PrecisionStopwatch;
import art.arcane.iris.util.common.format.C;
import art.arcane.volmlib.util.matter.IrisMatter;
@@ -153,7 +154,14 @@ public class IrisEngineMantle implements EngineMantle {
}
private Set<MantleFlag> getDisabledFlags() {
return disabledFlags.aquire(() -> Set.copyOf(getDimension().getDisabledComponents()));
return disabledFlags.aquire(() -> {
KList<MantleFlag> disabled = new KList<>();
disabled.addAll(getDimension().getDisabledComponents());
if (!getDimension().isCarvingEnabled()) {
disabled.addIfMissing(ReservedFlag.CARVED);
}
return Set.copyOf(disabled);
});
}
@Override

View File

@@ -29,6 +29,8 @@ import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.volmlib.util.matter.MatterCavern;
import java.util.Arrays;
public class IrisCaveCarver3D {
private static final byte LIQUID_AIR = 0;
private static final byte LIQUID_WATER = 1;
@@ -81,6 +83,27 @@ public class IrisCaveCarver3D {
}
public int carve(MantleWriter writer, int chunkX, int chunkZ) {
double[] fullWeights = new double[256];
Arrays.fill(fullWeights, 1D);
return carve(writer, chunkX, chunkZ, fullWeights, 0D, 0D);
}
public int carve(
MantleWriter writer,
int chunkX,
int chunkZ,
double[] columnWeights,
double minWeight,
double thresholdPenalty
) {
if (columnWeights == null || columnWeights.length < 256) {
double[] fullWeights = new double[256];
Arrays.fill(fullWeights, 1D);
columnWeights = fullWeights;
}
double resolvedMinWeight = Math.max(0D, Math.min(1D, minWeight));
double resolvedThresholdPenalty = Math.max(0D, thresholdPenalty);
int worldHeight = writer.getMantle().getWorldHeight();
int minY = Math.max(0, (int) Math.floor(profile.getVerticalRange().getMin()));
int maxY = Math.min(worldHeight - 1, (int) Math.ceil(profile.getVerticalRange().getMax()));
@@ -140,6 +163,9 @@ public class IrisCaveCarver3D {
surfaceBreakFloorY,
surfaceBreakColumn,
columnThreshold,
columnWeights,
resolvedMinWeight,
resolvedThresholdPenalty,
0D,
false
);
@@ -162,6 +188,9 @@ public class IrisCaveCarver3D {
surfaceBreakFloorY,
surfaceBreakColumn,
columnThreshold,
columnWeights,
resolvedMinWeight,
resolvedThresholdPenalty,
recoveryThresholdBoost,
true
);
@@ -185,6 +214,9 @@ public class IrisCaveCarver3D {
int[] surfaceBreakFloorY,
boolean[] surfaceBreakColumn,
double[] columnThreshold,
double[] columnWeights,
double minWeight,
double thresholdPenalty,
double thresholdBoost,
boolean skipExistingCarved
) {
@@ -195,6 +227,11 @@ public class IrisCaveCarver3D {
for (int lz = 0; lz < 16; lz++) {
int z = z0 + lz;
int index = (lx << 4) | lz;
double columnWeight = clampColumnWeight(columnWeights[index]);
if (columnWeight <= minWeight) {
continue;
}
int columnTopY = columnMaxY[index];
if (columnTopY < minY) {
continue;
@@ -203,7 +240,7 @@ public class IrisCaveCarver3D {
boolean breakColumn = surfaceBreakColumn[index];
int breakFloorY = surfaceBreakFloorY[index];
int surfaceY = columnSurface[index];
double threshold = columnThreshold[index] + thresholdBoost;
double threshold = columnThreshold[index] + thresholdBoost - ((1D - columnWeight) * thresholdPenalty);
for (int y = minY; y <= columnTopY; y += sampleStep) {
double localThreshold = threshold;
@@ -353,6 +390,22 @@ public class IrisCaveCarver3D {
return sampleDensity(x, y, z) > threshold;
}
private double clampColumnWeight(double weight) {
if (Double.isNaN(weight) || Double.isInfinite(weight)) {
return 0D;
}
if (weight <= 0D) {
return 0D;
}
if (weight >= 1D) {
return 1D;
}
return weight;
}
private double signed(double value) {
return (value * 2D) - 1D;
}

View File

@@ -18,26 +18,33 @@
package art.arcane.iris.engine.mantle.components;
import art.arcane.iris.engine.data.cache.Cache;
import art.arcane.iris.engine.mantle.ComponentFlag;
import art.arcane.iris.engine.mantle.EngineMantle;
import art.arcane.iris.engine.mantle.IrisMantleComponent;
import art.arcane.iris.engine.mantle.MantleWriter;
import art.arcane.iris.engine.object.IrisBiome;
import art.arcane.iris.engine.object.IrisCarving;
import art.arcane.iris.engine.object.IrisCaveProfile;
import art.arcane.iris.engine.object.IrisDimension;
import art.arcane.iris.engine.object.IrisRegion;
import art.arcane.iris.util.project.context.ChunkContext;
import art.arcane.volmlib.util.documentation.ChunkCoordinates;
import art.arcane.volmlib.util.mantle.flag.ReservedFlag;
import art.arcane.volmlib.util.math.RNG;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@ComponentFlag(ReservedFlag.CARVED)
public class MantleCarvingComponent extends IrisMantleComponent {
private static final int CHUNK_SIZE = 16;
private static final int CHUNK_AREA = CHUNK_SIZE * CHUNK_SIZE;
private static final int BLEND_RADIUS = 3;
private static final int FIELD_SIZE = CHUNK_SIZE + (BLEND_RADIUS * 2);
private static final double MIN_WEIGHT = 0.08D;
private static final double THRESHOLD_PENALTY = 0.24D;
private final Map<IrisCaveProfile, IrisCaveCarver3D> profileCarvers = new IdentityHashMap<>();
public MantleCarvingComponent(EngineMantle engineMantle) {
@@ -46,71 +53,147 @@ public class MantleCarvingComponent extends IrisMantleComponent {
@Override
public void generateLayer(MantleWriter writer, int x, int z, ChunkContext context) {
RNG rng = new RNG(Cache.key(x, z) + seed());
int xxx = 8 + (x << 4);
int zzz = 8 + (z << 4);
IrisRegion region = getComplex().getRegionStream().get(xxx, zzz);
IrisBiome surfaceBiome = getComplex().getTrueBiomeStream().get(xxx, zzz);
IrisCaveProfile caveBiomeProfile = resolveDominantCaveBiomeProfile(x, z);
carve(writer, rng, x, z, region, surfaceBiome, caveBiomeProfile);
}
@ChunkCoordinates
private void carve(MantleWriter writer, RNG rng, int cx, int cz, IrisRegion region, IrisBiome surfaceBiome, IrisCaveProfile caveBiomeProfile) {
IrisCaveProfile dimensionProfile = getDimension().getCaveProfile();
IrisCaveProfile surfaceBiomeProfile = surfaceBiome.getCaveProfile();
IrisCaveProfile regionProfile = region.getCaveProfile();
IrisCaveProfile activeProfile = resolveActiveProfile(dimensionProfile, regionProfile, surfaceBiomeProfile, caveBiomeProfile);
if (isProfileEnabled(activeProfile)) {
int carved = carveProfile(activeProfile, writer, cx, cz);
if (carved > 0) {
return;
}
if (activeProfile != regionProfile && isProfileEnabled(regionProfile)) {
carved = carveProfile(regionProfile, writer, cx, cz);
if (carved > 0) {
return;
}
}
if (activeProfile != surfaceBiomeProfile && isProfileEnabled(surfaceBiomeProfile)) {
carved = carveProfile(surfaceBiomeProfile, writer, cx, cz);
if (carved > 0) {
return;
}
}
if (activeProfile != dimensionProfile && isProfileEnabled(dimensionProfile)) {
carved = carveProfile(dimensionProfile, writer, cx, cz);
if (carved > 0) {
return;
}
}
List<WeightedProfile> weightedProfiles = resolveWeightedProfiles(x, z);
for (WeightedProfile weightedProfile : weightedProfiles) {
carveProfile(weightedProfile.profile, weightedProfile.columnWeights, writer, x, z);
}
carve(getDimension().getCarving(), writer, nextCarveRng(rng, cx, cz), cx, cz);
carve(surfaceBiome.getCarving(), writer, nextCarveRng(rng, cx, cz), cx, cz);
carve(region.getCarving(), writer, nextCarveRng(rng, cx, cz), cx, cz);
}
@ChunkCoordinates
private void carve(IrisCarving carving, MantleWriter writer, RNG rng, int cx, int cz) {
carving.doCarving(writer, rng, getEngineMantle().getEngine(), cx << 4, -1, cz << 4, 0);
}
private RNG nextCarveRng(RNG rng, int cx, int cz) {
return new RNG((rng.nextLong() * cx) + 490495L + cz);
}
@ChunkCoordinates
private int carveProfile(IrisCaveProfile profile, MantleWriter writer, int cx, int cz) {
if (!isProfileEnabled(profile)) {
return 0;
}
private void carveProfile(IrisCaveProfile profile, double[] columnWeights, MantleWriter writer, int cx, int cz) {
IrisCaveCarver3D carver = getCarver(profile);
return carver.carve(writer, cx, cz);
carver.carve(writer, cx, cz, columnWeights, MIN_WEIGHT, THRESHOLD_PENALTY);
}
private List<WeightedProfile> resolveWeightedProfiles(int chunkX, int chunkZ) {
IrisCaveProfile[] profileField = buildProfileField(chunkX, chunkZ);
Map<IrisCaveProfile, double[]> profileWeights = new IdentityHashMap<>();
for (int localX = 0; localX < CHUNK_SIZE; localX++) {
for (int localZ = 0; localZ < CHUNK_SIZE; localZ++) {
int columnIndex = (localX << 4) | localZ;
Map<IrisCaveProfile, Double> columnInfluence = sampleColumnInfluence(profileField, localX, localZ);
for (Map.Entry<IrisCaveProfile, Double> entry : columnInfluence.entrySet()) {
double[] weights = profileWeights.computeIfAbsent(entry.getKey(), key -> new double[CHUNK_AREA]);
weights[columnIndex] = entry.getValue();
}
}
}
List<WeightedProfile> weightedProfiles = new ArrayList<>();
for (Map.Entry<IrisCaveProfile, double[]> entry : profileWeights.entrySet()) {
IrisCaveProfile profile = entry.getKey();
double[] weights = entry.getValue();
double totalWeight = 0D;
double maxWeight = 0D;
for (double weight : weights) {
totalWeight += weight;
if (weight > maxWeight) {
maxWeight = weight;
}
}
if (maxWeight < MIN_WEIGHT) {
continue;
}
double averageWeight = totalWeight / CHUNK_AREA;
weightedProfiles.add(new WeightedProfile(profile, weights, averageWeight));
}
weightedProfiles.sort(Comparator.comparingDouble(WeightedProfile::averageWeight));
return weightedProfiles;
}
private Map<IrisCaveProfile, Double> sampleColumnInfluence(IrisCaveProfile[] profileField, int localX, int localZ) {
Map<IrisCaveProfile, Double> profileBlend = new IdentityHashMap<>();
int centerX = localX + BLEND_RADIUS;
int centerZ = localZ + BLEND_RADIUS;
double totalKernelWeight = 0D;
for (int offsetX = -BLEND_RADIUS; offsetX <= BLEND_RADIUS; offsetX++) {
for (int offsetZ = -BLEND_RADIUS; offsetZ <= BLEND_RADIUS; offsetZ++) {
int sampleX = centerX + offsetX;
int sampleZ = centerZ + offsetZ;
IrisCaveProfile profile = profileField[(sampleX * FIELD_SIZE) + sampleZ];
if (!isProfileEnabled(profile)) {
continue;
}
double kernelWeight = haloWeight(offsetX, offsetZ);
profileBlend.merge(profile, kernelWeight, Double::sum);
totalKernelWeight += kernelWeight;
}
}
if (totalKernelWeight <= 0D || profileBlend.isEmpty()) {
return Collections.emptyMap();
}
Map<IrisCaveProfile, Double> normalized = new IdentityHashMap<>();
for (Map.Entry<IrisCaveProfile, Double> entry : profileBlend.entrySet()) {
normalized.put(entry.getKey(), entry.getValue() / totalKernelWeight);
}
return normalized;
}
private IrisCaveProfile[] buildProfileField(int chunkX, int chunkZ) {
IrisCaveProfile[] profileField = new IrisCaveProfile[FIELD_SIZE * FIELD_SIZE];
int startX = (chunkX << 4) - BLEND_RADIUS;
int startZ = (chunkZ << 4) - BLEND_RADIUS;
for (int fieldX = 0; fieldX < FIELD_SIZE; fieldX++) {
int worldX = startX + fieldX;
for (int fieldZ = 0; fieldZ < FIELD_SIZE; fieldZ++) {
int worldZ = startZ + fieldZ;
profileField[(fieldX * FIELD_SIZE) + fieldZ] = resolveColumnProfile(worldX, worldZ);
}
}
return profileField;
}
private double haloWeight(int offsetX, int offsetZ) {
int edgeDistance = Math.max(Math.abs(offsetX), Math.abs(offsetZ));
return (BLEND_RADIUS + 1D) - edgeDistance;
}
private IrisCaveProfile resolveColumnProfile(int worldX, int worldZ) {
IrisCaveProfile resolved = null;
IrisCaveProfile dimensionProfile = getDimension().getCaveProfile();
if (isProfileEnabled(dimensionProfile)) {
resolved = dimensionProfile;
}
IrisRegion region = getComplex().getRegionStream().get(worldX, worldZ);
if (region != null) {
IrisCaveProfile regionProfile = region.getCaveProfile();
if (isProfileEnabled(regionProfile)) {
resolved = regionProfile;
}
}
IrisBiome surfaceBiome = getComplex().getTrueBiomeStream().get(worldX, worldZ);
if (surfaceBiome != null) {
IrisCaveProfile surfaceProfile = surfaceBiome.getCaveProfile();
if (isProfileEnabled(surfaceProfile)) {
resolved = surfaceProfile;
}
}
int surfaceY = getEngineMantle().getEngine().getHeight(worldX, worldZ, true);
int sampleY = Math.max(1, surfaceY - 56);
IrisBiome caveBiome = getEngineMantle().getEngine().getCaveBiome(worldX, sampleY, worldZ);
if (caveBiome != null) {
IrisCaveProfile caveProfile = caveBiome.getCaveProfile();
if (isProfileEnabled(caveProfile)) {
resolved = caveProfile;
}
}
return resolved;
}
private IrisCaveCarver3D getCarver(IrisCaveProfile profile) {
@@ -130,82 +213,23 @@ public class MantleCarvingComponent extends IrisMantleComponent {
return profile != null && profile.isEnabled();
}
@ChunkCoordinates
private IrisCaveProfile resolveDominantCaveBiomeProfile(int chunkX, int chunkZ) {
int[] offsets = new int[]{1, 4, 8, 12, 15};
Map<IrisCaveProfile, Integer> profileVotes = new IdentityHashMap<>();
int validSamples = 0;
IrisCaveProfile dominantProfile = null;
int dominantVotes = 0;
for (int offsetX : offsets) {
for (int offsetZ : offsets) {
int sampleX = (chunkX << 4) + offsetX;
int sampleZ = (chunkZ << 4) + offsetZ;
int surfaceY = getEngineMantle().getEngine().getHeight(sampleX, sampleZ, true);
int sampleY = Math.max(1, surfaceY - 56);
IrisBiome caveBiome = getEngineMantle().getEngine().getCaveBiome(sampleX, sampleY, sampleZ);
if (caveBiome == null) {
continue;
}
IrisCaveProfile profile = caveBiome.getCaveProfile();
if (!isProfileEnabled(profile)) {
continue;
}
int votes = profileVotes.getOrDefault(profile, 0) + 1;
profileVotes.put(profile, votes);
validSamples++;
if (votes > dominantVotes) {
dominantVotes = votes;
dominantProfile = profile;
}
}
}
if (dominantProfile == null || validSamples <= 0) {
return null;
}
int requiredVotes = Math.max(13, (int) Math.ceil(validSamples * 0.65D));
if (dominantVotes < requiredVotes) {
return null;
}
return dominantProfile;
}
private IrisCaveProfile resolveActiveProfile(IrisCaveProfile dimensionProfile, IrisCaveProfile regionProfile, IrisCaveProfile surfaceBiomeProfile, IrisCaveProfile caveBiomeProfile) {
if (isProfileEnabled(caveBiomeProfile)) {
return caveBiomeProfile;
}
if (isProfileEnabled(surfaceBiomeProfile)) {
return surfaceBiomeProfile;
}
if (isProfileEnabled(regionProfile)) {
return regionProfile;
}
return dimensionProfile;
}
protected int computeRadius() {
IrisDimension dimension = getDimension();
int max = 0;
return 0;
}
max = Math.max(max, dimension.getCarving().getMaxRange(getData(), 0));
private static final class WeightedProfile {
private final IrisCaveProfile profile;
private final double[] columnWeights;
private final double averageWeight;
for (IrisRegion i : dimension.getAllRegions(this::getData)) {
max = Math.max(max, i.getCarving().getMaxRange(getData(), 0));
private WeightedProfile(IrisCaveProfile profile, double[] columnWeights, double averageWeight) {
this.profile = profile;
this.columnWeights = columnWeights;
this.averageWeight = averageWeight;
}
for (IrisBiome i : dimension.getAllBiomes(this::getData)) {
max = Math.max(max, i.getCarving().getMaxRange(getData(), 0));
private double averageWeight() {
return averageWeight;
}
return max;
}
}

View File

@@ -24,9 +24,9 @@ import art.arcane.iris.util.project.stream.interpolation.Interpolated;
import java.util.List;
public interface IRare {
static <T extends IRare> ProceduralStream<T> stream(ProceduralStream<Double> noise, List<T> possibilities, boolean legacyRarity) {
return ProceduralStream.of(legacyRarity ? (x, z) -> pickLegacy(possibilities, noise.get(x, z)) : (x, z) -> pick(possibilities, noise.get(x, z)),
legacyRarity ? (x, y, z) -> pickLegacy(possibilities, noise.get(x, y, z)) : (x, y, z) -> pick(possibilities, noise.get(x, y, z)),
static <T extends IRare> ProceduralStream<T> stream(ProceduralStream<Double> noise, List<T> possibilities) {
return ProceduralStream.of((x, z) -> pick(possibilities, noise.get(x, z)),
(x, y, z) -> pick(possibilities, noise.get(x, y, z)),
new Interpolated<T>() {
@Override
public double toDouble(T t) {
@@ -89,63 +89,6 @@ public interface IRare {
return possibilities.getLast();
}
static <T extends IRare> T pickLegacy(List<T> possibilities, double noiseValue) {
if (possibilities.isEmpty()) {
return null;
}
if (possibilities.size() == 1) {
return possibilities.get(0);
}
int totalWeight = 0; // This is he baseline
int buffer = 0;
for (T i : possibilities) { // Im adding all of the rarity together
totalWeight += i.getRarity();
}
double threshold = totalWeight * (possibilities.size() - 1) * noiseValue;
for (T i : possibilities) {
buffer += totalWeight - i.getRarity();
if (buffer >= threshold) {
return i;
}
}
return possibilities.get(possibilities.size() - 1);
}
static <T extends IRare> T pickOld(List<T> possibilities, double noiseValue) {
if (possibilities.isEmpty()) {
return null;
}
if (possibilities.size() == 1) {
return possibilities.get(0);
}
double completeWeight = 0.0;
double highestWeight = 0.0;
for (T item : possibilities) {
double weight = Math.max(item.getRarity(), 1);
highestWeight = Math.max(highestWeight, weight);
completeWeight += weight;
}
double r = noiseValue * completeWeight;
double countWeight = 0.0;
for (T item : possibilities) {
double weight = Math.max(highestWeight - Math.max(item.getRarity(), 1), 1);
countWeight += weight;
if (countWeight >= r) {
return item;
}
}
return possibilities.get(possibilities.size() - 1);
}
static int get(Object v) {
return v instanceof IRare ? Math.max(1, ((IRare) v).getRarity()) : 1;
}

View File

@@ -100,8 +100,6 @@ public class IrisBiome extends IrisRegistrant implements IRare {
private boolean lockLayers = false;
@Desc("The max layers to iterate below the surface for locked layer biomes (mesa).")
private int lockLayersMax = 7;
@Desc("Carving configuration for the dimension")
private IrisCarving carving = new IrisCarving();
@Desc("Profile-driven 3D cave configuration")
private IrisCaveProfile caveProfile = new IrisCaveProfile();
@Desc("Configuration of fluid bodies such as rivers & lakes")

View File

@@ -1,139 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* 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 art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.mantle.MantleWriter;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.Snippet;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.documentation.BlockCoordinates;
import art.arcane.volmlib.util.math.RNG;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Snippet("carving")
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Desc("Represents a carving configuration")
@Data
public class IrisCarving {
@ArrayType(type = IrisCavePlacer.class, min = 1)
@Desc("Define cave placers")
private KList<IrisCavePlacer> caves = new KList<>();
@ArrayType(type = IrisRavinePlacer.class, min = 1)
@Desc("Define ravine placers")
private KList<IrisRavinePlacer> ravines = new KList<>();
@ArrayType(type = IrisElipsoid.class, min = 1)
@Desc("Define elipsoids")
private KList<IrisElipsoid> elipsoids = new KList<>();
@ArrayType(type = IrisSphere.class, min = 1)
@Desc("Define spheres")
private KList<IrisSphere> spheres = new KList<>();
@ArrayType(type = IrisPyramid.class, min = 1)
@Desc("Define pyramids")
private KList<IrisPyramid> pyramids = new KList<>();
@BlockCoordinates
public void doCarving(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z, int depth) {
doCarving(writer, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, depth, -1);
}
@BlockCoordinates
public void doCarving(MantleWriter writer, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) {
int nextRecursion = recursion + 1;
if (caves.isNotEmpty()) {
for (IrisCavePlacer i : caves) {
if (recursion > i.getMaxRecursion()) continue;
i.generateCave(writer, rng, base, engine, x, y, z, nextRecursion, waterHint);
}
}
if (ravines.isNotEmpty()) {
for (IrisRavinePlacer i : ravines) {
if (recursion > i.getMaxRecursion()) continue;
i.generateRavine(writer, rng, base, engine, x, y, z, nextRecursion, waterHint);
}
}
if (spheres.isNotEmpty()) {
for (IrisSphere i : spheres) {
if (rng.nextInt(i.getRarity()) == 0) {
i.generate(base, engine, writer, x, y, z);
}
}
}
if (elipsoids.isNotEmpty()) {
for (IrisElipsoid i : elipsoids) {
if (rng.nextInt(i.getRarity()) == 0) {
i.generate(base, engine, writer, x, y, z);
}
}
}
if (pyramids.isNotEmpty()) {
for (IrisPyramid i : pyramids) {
if (rng.nextInt(i.getRarity()) == 0) {
i.generate(base, engine, writer, x, y, z);
}
}
}
}
public int getMaxRange(IrisData data, int recursion) {
int max = 0;
int nextRecursion = recursion + 1;
for (IrisCavePlacer i : caves) {
if (recursion > i.getMaxRecursion()) continue;
max = Math.max(max, i.getSize(data, nextRecursion));
}
for (IrisRavinePlacer i : ravines) {
if (recursion > i.getMaxRecursion()) continue;
max = Math.max(max, i.getSize(data, nextRecursion));
}
if (elipsoids.isNotEmpty()) {
max = (int) Math.max(elipsoids.stream().mapToDouble(IrisElipsoid::maxSize).max().getAsDouble(), max);
}
if (spheres.isNotEmpty()) {
max = (int) Math.max(spheres.stream().mapToDouble(IrisSphere::maxSize).max().getAsDouble(), max);
}
if (pyramids.isNotEmpty()) {
max = (int) Math.max(pyramids.stream().mapToDouble(IrisPyramid::maxSize).max().getAsDouble(), max);
}
return max;
}
}

View File

@@ -1,119 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* 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 art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.core.loader.IrisRegistrant;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.mantle.MantleWriter;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.collection.KSet;
import art.arcane.volmlib.util.json.JSONObject;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.volmlib.util.matter.MatterCavern;
import art.arcane.iris.util.project.noise.CNG;
import art.arcane.iris.util.common.plugin.VolmitSender;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Desc("Translate objects")
@Data
public class IrisCave extends IrisRegistrant {
@Desc("Define the shape of this cave")
private IrisWorm worm = new IrisWorm();
@Desc("Define potential forking features")
private IrisCarving fork = new IrisCarving();
@RegistryListResource(IrisBiome.class)
@Desc("Force this cave to only generate the specified custom biome")
private String customBiome = "";
@Desc("Limit the worm from ever getting higher or lower than this range")
private IrisRange verticalRange = new IrisRange(3, 255);
@Desc("Shape of the caves")
private IrisCaveShape shape = new IrisCaveShape();
@Override
public String getFolderName() {
return "caves";
}
@Override
public String getTypeName() {
return "Cave";
}
public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) {
generate(writer, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1, true);
}
public void generate(MantleWriter writer, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint, boolean breakSurface) {
double girth = getWorm().getGirth().get(base.nextParallelRNG(465156), x, z, engine.getData());
KList<IrisPosition> points = getWorm().generate(base.nextParallelRNG(784684), engine.getData(), writer, verticalRange, x, y, z, breakSurface, girth + 9);
int highestWater = Math.max(waterHint, -1);
if (highestWater == -1) {
for (IrisPosition i : points) {
double yy = i.getY() + girth;
int th = engine.getHeight(x, z, true);
if (yy > th && th < engine.getDimension().getFluidHeight()) {
highestWater = Math.max(highestWater, (int) yy);
break;
}
}
}
int h = Math.min(highestWater, engine.getDimension().getFluidHeight());
for (IrisPosition i : points) {
fork.doCarving(writer, rng, base, engine, i.getX(), i.getY(), i.getZ(), recursion, h);
}
MatterCavern c = new MatterCavern(true, customBiome, (byte) 0);
MatterCavern w = new MatterCavern(true, customBiome, (byte) 1);
CNG cng = shape.getNoise(base.nextParallelRNG(8131545), engine);
KSet<IrisPosition> mask = shape.getMasked(rng, engine);
writer.setNoiseMasked(points,
girth, shape.getNoiseThreshold() < 0 ? cng.noise(x, y, z) : shape.getNoiseThreshold(), cng, mask, true,
(xf, yf, zf) -> yf <= h ? w : c);
}
@Override
public void scanForErrors(JSONObject p, VolmitSender sender) {
}
public int getMaxSize(IrisData data, int depth) {
return (int) (Math.ceil(getWorm().getGirth().getMax() * 2) + getWorm().getMaxDistance() + fork.getMaxRange(data, depth));
}
}

View File

@@ -1,111 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* 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 art.arcane.iris.engine.object;
import art.arcane.iris.Iris;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.mantle.MantleWriter;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.volmlib.util.math.RNG;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.concurrent.atomic.AtomicBoolean;
@Snippet("cave-placer")
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Desc("Translate objects")
@Data
public class IrisCavePlacer implements IRare {
private transient final AtomicCache<IrisCave> caveCache = new AtomicCache<>();
private transient final AtomicBoolean fail = new AtomicBoolean(false);
@Required
@Desc("Typically a 1 in RARITY on a per chunk/fork basis")
@MinNumber(1)
private int rarity = 15;
@MinNumber(1)
@Required
@Desc("The cave to place")
@RegistryListResource(IrisCave.class)
private String cave;
@MinNumber(1)
@MaxNumber(256)
@Desc("The maximum recursion depth")
private int maxRecursion = 16;
@Desc("If set to true, this cave is allowed to break the surface")
private boolean breakSurface = true;
@Desc("The height range this cave can spawn at. If breakSurface is false, the output of this range will be clamped by the current world height to prevent surface breaking.")
private IrisStyledRange caveStartHeight = new IrisStyledRange(13, 120, new IrisGeneratorStyle(NoiseStyle.STATIC));
public IrisCave getRealCave(IrisData data) {
return caveCache.aquire(() -> data.getCaveLoader().load(getCave()));
}
public void generateCave(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z) {
generateCave(mantle, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1);
}
public void generateCave(MantleWriter mantle, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) {
if (fail.get()) {
return;
}
if (rng.nextInt(rarity) != 0) {
return;
}
IrisData data = engine.getData();
IrisCave cave = getRealCave(data);
if (cave == null) {
Iris.warn("Unable to locate cave for generation!");
fail.set(true);
return;
}
if (y == -1) {
int h = (int) caveStartHeight.get(base, x, z, data);
int ma = breakSurface ? h : (int) (engine.getComplex().getHeightStream().get(x, z) - 9);
y = Math.min(h, ma);
}
try {
cave.generate(mantle, rng, base, engine, x + rng.nextInt(15), y, z + rng.nextInt(15), recursion, waterHint, breakSurface);
} catch (Throwable e) {
e.printStackTrace();
fail.set(true);
}
}
public int getSize(IrisData data, int depth) {
IrisCave cave = getRealCave(data);
if (cave != null) {
return cave.getMaxSize(data, depth);
}
return 32;
}
}

View File

@@ -140,16 +140,19 @@ public class IrisDimension extends IrisRegistrant {
private boolean postProcessing = true;
@Desc("Add slabs in post processing")
private boolean postProcessingSlabs = true;
@Desc("Add painted walls in post processing")
private boolean postProcessingWalls = true;
@Desc("Carving configuration for the dimension")
private IrisCarving carving = new IrisCarving();
@Desc("Add painted walls in post processing")
private boolean postProcessingWalls = true;
@Desc("Enable or disable all carving for this dimension")
private boolean carvingEnabled = true;
@Desc("Profile-driven 3D cave configuration")
private IrisCaveProfile caveProfile = new IrisCaveProfile();
@Desc("Configuration of fluid bodies such as rivers & lakes")
private IrisFluidBodies fluidBodies = new IrisFluidBodies();
@Desc("forceConvertTo320Height")
private Boolean forceConvertTo320Height = false;
@ArrayType(type = IrisExternalDatapack.class, min = 1)
@Desc("Pack-scoped external datapack sources for structure import and optional vanilla replacement")
private KList<IrisExternalDatapack> externalDatapacks = new KList<>();
@Desc("forceConvertTo320Height")
private Boolean forceConvertTo320Height = false;
@Desc("The world environment")
private Environment environment = Environment.NORMAL;
@RegistryListResource(IrisRegion.class)
@@ -255,12 +258,10 @@ public class IrisDimension extends IrisRegistrant {
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> dataScripts = new KList<>();
@Desc("A list of scripts executed on chunk update\nFile extension: .update.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> chunkUpdateScripts = new KList<>();
@Desc("Use legacy rarity instead of modern one\nWARNING: Changing this may break expressions and image maps")
private boolean legacyRarity = true;
@Desc("A list of scripts executed on chunk update\nFile extension: .update.kts")
@RegistryListResource(IrisScript.class)
@ArrayType(type = String.class, min = 1)
private KList<String> chunkUpdateScripts = new KList<>();
public int getMaxHeight() {
return (int) getDimensionHeight().getMax();

View File

@@ -1,60 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* 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 art.arcane.iris.engine.object;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.mantle.MantleWriter;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.volmlib.util.matter.MatterCavern;
import art.arcane.volmlib.util.matter.slices.CavernMatter;
import lombok.Data;
@Snippet("carving-elipsoid")
@Desc("Represents an procedural eliptical shape")
@Data
public class IrisElipsoid implements IRare {
private transient final AtomicCache<MatterCavern> matterNodeCache = new AtomicCache<>();
@Required
@Desc("Typically a 1 in RARITY on a per fork basis")
@MinNumber(1)
private int rarity = 1;
@RegistryListResource(IrisBiome.class)
@Desc("Force this cave to only generate the specified custom biome")
private String customBiome = "";
@Desc("The styled random radius for x")
private IrisStyledRange xRadius = new IrisStyledRange(1, 5, new IrisGeneratorStyle(NoiseStyle.STATIC));
@Desc("The styled random radius for y")
private IrisStyledRange yRadius = new IrisStyledRange(1, 5, new IrisGeneratorStyle(NoiseStyle.STATIC));
@Desc("The styled random radius for z")
private IrisStyledRange zRadius = new IrisStyledRange(1, 5, new IrisGeneratorStyle(NoiseStyle.STATIC));
@SuppressWarnings("SuspiciousNameCombination")
public void generate(RNG rng, Engine engine, MantleWriter writer, int x, int y, int z) {
writer.setElipsoid(x, y, z,
xRadius.get(rng, z, y, engine.getData()),
yRadius.get(rng, x, z, engine.getData()),
zRadius.get(rng, y, x, engine.getData()), true, matterNodeCache.aquire(() -> CavernMatter.get(getCustomBiome(), 0)));
}
public double maxSize() {
return Math.max(xRadius.getMax(), Math.max(yRadius.getMax(), zRadius.getMax()));
}
}

View File

@@ -0,0 +1,32 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.Desc;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@Desc("Defines a pack-scoped external datapack source for structure import and optional vanilla replacement")
public class IrisExternalDatapack {
@Desc("Stable id for this external datapack entry")
private String id = "";
@Desc("Datapack source URL. Modrinth version page URLs are supported.")
private String url = "";
@Desc("Enable or disable this external datapack entry")
private boolean enabled = true;
@Desc("If true, Iris hard-fails startup when this external datapack cannot be synced/imported/installed")
private boolean required = false;
@Desc("If true, minecraft namespace worldgen assets may replace vanilla targets listed in replaceTargets")
private boolean replaceVanilla = false;
@Desc("Explicit replacement targets for minecraft namespace assets")
private IrisExternalDatapackReplaceTargets replaceTargets = new IrisExternalDatapackReplaceTargets();
}

View File

@@ -0,0 +1,44 @@
package art.arcane.iris.engine.object;
import art.arcane.iris.engine.object.annotations.ArrayType;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.volmlib.util.collection.KList;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
@Desc("Explicit minecraft namespace targets that may be replaced by an external datapack")
public class IrisExternalDatapackReplaceTargets {
@ArrayType(type = String.class, min = 1)
@Desc("Structure ids that may be replaced when replaceVanilla is enabled")
private KList<String> structures = new KList<>();
@ArrayType(type = String.class, min = 1)
@Desc("Structure set ids that may be replaced when replaceVanilla is enabled")
private KList<String> structureSets = new KList<>();
@ArrayType(type = String.class, min = 1)
@Desc("Template pool ids that may be replaced when replaceVanilla is enabled")
private KList<String> templatePools = new KList<>();
@ArrayType(type = String.class, min = 1)
@Desc("Processor list ids that may be replaced when replaceVanilla is enabled")
private KList<String> processorLists = new KList<>();
@ArrayType(type = String.class, min = 1)
@Desc("Biome has_structure tag ids that may be replaced when replaceVanilla is enabled")
private KList<String> biomeHasStructureTags = new KList<>();
public boolean hasAnyTargets() {
return !structures.isEmpty()
|| !structureSets.isEmpty()
|| !templatePools.isEmpty()
|| !processorLists.isEmpty()
|| !biomeHasStructureTags.isEmpty();
}
}

View File

@@ -1,53 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* 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 art.arcane.iris.engine.object;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.mantle.MantleWriter;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.volmlib.util.matter.MatterCavern;
import art.arcane.volmlib.util.matter.slices.CavernMatter;
import lombok.Data;
@Snippet("carving-pyramid")
@Desc("Represents an procedural eliptical shape")
@Data
public class IrisPyramid implements IRare {
private transient final AtomicCache<MatterCavern> matterNodeCache = new AtomicCache<>();
@Required
@Desc("Typically a 1 in RARITY on a per fork basis")
@MinNumber(1)
private int rarity = 1;
@RegistryListResource(IrisBiome.class)
@Desc("Force this cave to only generate the specified custom biome")
private String customBiome = "";
@Desc("The styled random radius for x")
private IrisStyledRange baseWidth = new IrisStyledRange(1, 5, new IrisGeneratorStyle(NoiseStyle.STATIC));
public void generate(RNG rng, Engine engine, MantleWriter writer, int x, int y, int z) {
writer.setPyramid(x, y, z, matterNodeCache.aquire(() -> CavernMatter.get(getCustomBiome(), 0)),
(int) baseWidth.get(rng, z, y, engine.getData()), true);
}
public double maxSize() {
return baseWidth.getMax();
}
}

View File

@@ -1,189 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* 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 art.arcane.iris.engine.object;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.core.loader.IrisRegistrant;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.mantle.MantleWriter;
import art.arcane.iris.engine.object.annotations.Desc;
import art.arcane.iris.engine.object.annotations.MaxNumber;
import art.arcane.iris.engine.object.annotations.MinNumber;
import art.arcane.iris.engine.object.annotations.RegistryListResource;
import art.arcane.volmlib.util.collection.KList;
import art.arcane.volmlib.util.json.JSONObject;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.volmlib.util.matter.MatterCavern;
import art.arcane.iris.util.project.noise.CNG;
import art.arcane.iris.util.common.plugin.VolmitSender;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Desc("Translate objects")
@Data
public class IrisRavine extends IrisRegistrant {
@Desc("Define the shape of this ravine (2d, ignores Y)")
private IrisWorm worm = new IrisWorm();
@RegistryListResource(IrisBiome.class)
@Desc("Force this cave to only generate the specified custom biome")
private String customBiome = "";
@Desc("Define potential forking features")
private IrisCarving fork = new IrisCarving();
@Desc("The style used to determine the curvature of this worm's y")
private IrisShapedGeneratorStyle depthStyle = new IrisShapedGeneratorStyle(NoiseStyle.PERLIN, 5, 18);
@Desc("The style used to determine the curvature of this worm's y")
private IrisShapedGeneratorStyle baseWidthStyle = new IrisShapedGeneratorStyle(NoiseStyle.PERLIN, 3, 6);
@MinNumber(1)
@MaxNumber(100)
@Desc("The angle at which the ravine widens as it gets closer to the surface")
private double angle = 18;
@MinNumber(1)
@MaxNumber(100)
@Desc("The angle at which the ravine widens as it gets closer to the surface")
private double topAngle = 38;
@Desc("To fill this cave with lava, set the lava level to a height from the bottom most point of the cave.")
private int lavaLevel = -1;
@Desc("How many worm nodes must be placed to actually generate a ravine? Higher reduces the chances but also reduces ravine 'holes'")
private int nodeThreshold = 5;
@MinNumber(1)
@MaxNumber(8)
@Desc("The thickness of the ravine ribs")
private double ribThickness = 3;
@Override
public String getFolderName() {
return "ravines";
}
@Override
public String getTypeName() {
return "Ravine";
}
public void generate(MantleWriter writer, RNG rng, Engine engine, int x, int y, int z) {
generate(writer, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1);
}
public void generate(MantleWriter writer, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) {
KList<IrisPosition> pos = getWorm().generate(base.nextParallelRNG(879615), engine.getData(), writer, null, x, y, z, true, 0);
CNG dg = depthStyle.getGenerator().create(base.nextParallelRNG(7894156), engine.getData());
CNG bw = baseWidthStyle.getGenerator().create(base.nextParallelRNG(15315456), engine.getData());
int highestWater = Math.max(waterHint, -1);
boolean water = false;
if (highestWater == -1) {
for (IrisPosition i : pos) {
int rsurface = y == -1 ? engine.getComplex().getHeightStream().get(x, z).intValue() : y;
int depth = (int) Math.round(dg.fitDouble(depthStyle.getMin(), depthStyle.getMax(), i.getX(), i.getZ()));
int surface = (int) Math.round(rsurface - depth * 0.45);
int yy = surface + depth;
int th = engine.getHeight(x, z, true);
if (yy > th && th < engine.getDimension().getFluidHeight()) {
highestWater = Math.max(highestWater, yy);
water = true;
break;
}
}
} else {
water = true;
}
MatterCavern c = new MatterCavern(true, customBiome, (byte) (water ? 1 : 0));
MatterCavern l = new MatterCavern(true, customBiome, (byte) 2);
if (pos.size() < nodeThreshold) {
return;
}
for (IrisPosition p : pos) {
int rsurface = y == -1 ? engine.getComplex().getHeightStream().get(x, z).intValue() : y;
int depth = (int) Math.round(dg.fitDouble(depthStyle.getMin(), depthStyle.getMax(), p.getX(), p.getZ()));
int width = (int) Math.round(bw.fitDouble(baseWidthStyle.getMin(), baseWidthStyle.getMax(), p.getX(), p.getZ()));
int surface = (int) Math.round(rsurface - depth * 0.45);
fork.doCarving(writer, rng, base, engine, p.getX(), rng.i(surface - depth, surface), p.getZ(), recursion, highestWater);
for (int i = surface + depth; i >= surface; i--) {
if (i % ribThickness == 0) {
double v = width + ((((surface + depth) - i) * (angle / 360D)));
if (v <= 0.25) {
break;
}
if (i <= ribThickness + 2) {
break;
}
if (lavaLevel >= 0 && i <= lavaLevel + (surface - depthStyle.getMid())) {
writer.setElipsoid(p.getX(), i, p.getZ(), v, ribThickness, v, true, l);
} else {
writer.setElipsoid(p.getX(), i, p.getZ(), v, ribThickness, v, true, c);
}
}
}
for (int i = surface - depth; i <= surface; i++) {
if (i % ribThickness == 0) {
double v = width - ((((surface - depth) - i) * (angle / 360D)));
if (v <= 0.25) {
break;
}
if (i <= ribThickness + 2) {
break;
}
if (lavaLevel >= 0 && i <= lavaLevel + (surface - depthStyle.getMid())) {
writer.setElipsoid(p.getX(), i, p.getZ(), v, ribThickness, v, true, l);
} else {
writer.setElipsoid(p.getX(), i, p.getZ(), v, ribThickness, v, true, c);
}
}
}
}
}
@Override
public void scanForErrors(JSONObject p, VolmitSender sender) {
}
public int getMaxSize(IrisData data, int depth) {
return getWorm().getMaxDistance() + fork.getMaxRange(data, depth);
}
}

View File

@@ -1,97 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* 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 art.arcane.iris.engine.object;
import art.arcane.iris.Iris;
import art.arcane.iris.core.loader.IrisData;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.mantle.MantleWriter;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.volmlib.util.math.RNG;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.util.concurrent.atomic.AtomicBoolean;
@Snippet("ravine-placer")
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
@Desc("Translate objects")
@Data
public class IrisRavinePlacer implements IRare {
private transient final AtomicCache<IrisRavine> ravineCache = new AtomicCache<>();
private transient final AtomicBoolean fail = new AtomicBoolean(false);
@Required
@Desc("Typically a 1 in RARITY on a per chunk/fork basis")
@MinNumber(1)
private int rarity = 15;
@MinNumber(1)
@Required
@Desc("The ravine to place")
@RegistryListResource(IrisRavine.class)
private String ravine;
@MinNumber(1)
@MaxNumber(256)
@Desc("The maximum recursion depth")
private int maxRecursion = 100;
public IrisRavine getRealRavine(IrisData data) {
return ravineCache.aquire(() -> data.getRavineLoader().load(getRavine()));
}
public void generateRavine(MantleWriter mantle, RNG rng, Engine engine, int x, int y, int z) {
generateRavine(mantle, rng, new RNG(engine.getSeedManager().getCarve()), engine, x, y, z, 0, -1);
}
public void generateRavine(MantleWriter mantle, RNG rng, RNG base, Engine engine, int x, int y, int z, int recursion, int waterHint) {
if (fail.get()) {
return;
}
if (rng.nextInt(rarity) != 0) {
return;
}
IrisData data = engine.getData();
IrisRavine ravine = getRealRavine(data);
if (ravine == null) {
Iris.warn("Unable to locate ravine for generation!");
fail.set(true);
return;
}
try {
int xx = x + rng.nextInt(15);
int zz = z + rng.nextInt(15);
ravine.generate(mantle, rng, base, engine, xx, y, zz, recursion, waterHint);
} catch (Throwable e) {
e.printStackTrace();
fail.set(true);
}
}
public int getSize(IrisData data, int depth) {
return getRealRavine(data).getMaxSize(data, depth);
}
}

View File

@@ -112,8 +112,6 @@ public class IrisRegion extends IrisRegistrant implements IRare {
@MinNumber(0.0001)
@Desc("How large cave biomes are in this region")
private double caveBiomeZoom = 1;
@Desc("Carving configuration for the dimension")
private IrisCarving carving = new IrisCarving();
@Desc("Profile-driven 3D cave configuration")
private IrisCaveProfile caveProfile = new IrisCaveProfile();
@Desc("Configuration of fluid bodies such as rivers & lakes")

View File

@@ -1,52 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* 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 art.arcane.iris.engine.object;
import art.arcane.iris.engine.data.cache.AtomicCache;
import art.arcane.iris.engine.framework.Engine;
import art.arcane.iris.engine.mantle.MantleWriter;
import art.arcane.iris.engine.object.annotations.*;
import art.arcane.volmlib.util.math.RNG;
import art.arcane.volmlib.util.matter.MatterCavern;
import art.arcane.volmlib.util.matter.slices.CavernMatter;
import lombok.Data;
@Snippet("carving-sphere")
@Desc("Represents an procedural eliptical shape")
@Data
public class IrisSphere implements IRare {
private transient final AtomicCache<MatterCavern> matterNodeCache = new AtomicCache<>();
@Required
@Desc("Typically a 1 in RARITY on a per fork basis")
@MinNumber(1)
private int rarity = 1;
@RegistryListResource(IrisBiome.class)
@Desc("Force this cave to only generate the specified custom biome")
private String customBiome = "";
@Desc("The styled random radius for x")
private IrisStyledRange radius = new IrisStyledRange(1, 5, new IrisGeneratorStyle(NoiseStyle.STATIC));
public void generate(RNG rng, Engine engine, MantleWriter writer, int x, int y, int z) {
writer.setSphere(x, y, z, radius.get(rng, z, y, engine.getData()), true, matterNodeCache.aquire(() -> CavernMatter.get(getCustomBiome(), 0)));
}
public double maxSize() {
return radius.getMax();
}
}

View File

@@ -1,33 +0,0 @@
/*
* Iris is a World Generator for Minecraft Bukkit Servers
* Copyright (c) 2022 Arcane Arts (Volmit Software)
*
* 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 art.arcane.iris.util.common.director.handlers;
import art.arcane.iris.engine.object.IrisCave;
import art.arcane.iris.util.common.director.specialhandlers.RegistrantHandler;
public class CaveHandler extends RegistrantHandler<IrisCave> {
public CaveHandler() {
super(IrisCave.class, true);
}
@Override
public String getRandomDefault() {
return "cave";
}
}

View File

@@ -18,7 +18,6 @@
package art.arcane.iris.util.project.noise;
import art.arcane.iris.core.IrisSettings;
import art.arcane.iris.util.project.interpolation.InterpolationMethod;
public enum NoiseType {
WHITE(WhiteNoise::new),
@@ -97,7 +96,6 @@ public enum NoiseType {
}
public NoiseGenerator create(long seed) {
if (IrisSettings.get().getGenerator().offsetNoiseTypes) return f.create(seed).offset(seed);
else return f.create(seed);
return f.create(seed).offset(seed);
}
}

View File

@@ -352,16 +352,16 @@ public interface ProceduralStream<T> extends ProceduralLayer, Interpolated<T> {
return new SelectionStream<V>(this, rarityTypes);
}
default <V extends IRare> ProceduralStream<V> selectRarity(List<V> types, boolean legacy) {
return IRare.stream(this.forceDouble(), types, legacy);
default <V extends IRare> ProceduralStream<V> selectRarity(List<V> types) {
return IRare.stream(this.forceDouble(), types);
}
default <V> ProceduralStream<IRare> selectRarity(List<V> types, Function<V, IRare> loader, boolean legacy) {
default <V> ProceduralStream<IRare> selectRarity(List<V> types, Function<V, IRare> loader) {
List<IRare> r = new ArrayList<>();
for (V f : types) {
r.add(loader.apply(f));
}
return selectRarity(r, legacy);
return selectRarity(r);
}
default <V> int countPossibilities(List<V> types, Function<V, IRare> loader) {