Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement linear patterns using RandomPattern + SimpleRandom #2630

Merged
merged 1 commit into from Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -2,7 +2,7 @@

import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.extension.factory.parser.RichParser;
import com.fastasyncworldedit.core.function.pattern.Linear2DBlockPattern;
import com.fastasyncworldedit.core.math.random.Linear2DRandom;
import com.google.common.base.Preconditions;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.SuggestionHelper;
Expand All @@ -14,7 +14,6 @@
import com.sk89q.worldedit.world.block.BlockStateHolder;

import javax.annotation.Nonnull;
import java.util.Set;
import java.util.stream.Stream;

public class Linear2DPatternParser extends RichParser<Pattern> {
Expand Down Expand Up @@ -59,9 +58,8 @@ protected Pattern parseFromInput(@Nonnull String[] arguments, ParserContext cont
zScale = Integer.parseInt(arguments[2]);
Preconditions.checkArgument(zScale != 0);
}
if (inner instanceof RandomPattern) {
Set<Pattern> patterns = ((RandomPattern) inner).getPatterns();
return new Linear2DBlockPattern(patterns.toArray(new Pattern[0]), xScale, zScale);
if (inner instanceof RandomPattern rp) {
return new RandomPattern(new Linear2DRandom(xScale, zScale), rp);
}
throw new InputParseException(TextComponent.of("Pattern " + inner.getClass().getSimpleName()
+ " cannot be used with " + getPrefix()));
Expand Down
Expand Up @@ -2,7 +2,7 @@

import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.extension.factory.parser.RichParser;
import com.fastasyncworldedit.core.function.pattern.Linear3DBlockPattern;
import com.fastasyncworldedit.core.math.random.Linear3DRandom;
import com.google.common.base.Preconditions;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.command.util.SuggestionHelper;
Expand All @@ -14,7 +14,6 @@
import com.sk89q.worldedit.world.block.BlockStateHolder;

import javax.annotation.Nonnull;
import java.util.Set;
import java.util.stream.Stream;

public class Linear3DPatternParser extends RichParser<Pattern> {
Expand Down Expand Up @@ -64,9 +63,8 @@ protected Pattern parseFromInput(@Nonnull String[] arguments, ParserContext cont
zScale = Integer.parseInt(arguments[3]);
Preconditions.checkArgument(zScale != 0);
}
if (inner instanceof RandomPattern) {
Set<Pattern> patterns = ((RandomPattern) inner).getPatterns();
return new Linear3DBlockPattern(patterns.toArray(new Pattern[0]), xScale, yScale, zScale);
if (inner instanceof RandomPattern rp) {
return new RandomPattern(new Linear3DRandom(xScale, yScale, zScale), rp);
}
throw new InputParseException(TextComponent.of("Pattern " + inner.getClass().getSimpleName()
+ " cannot be used with " + getPrefix()));
Expand Down
Expand Up @@ -9,6 +9,11 @@

import static java.lang.Math.floorDiv;

/**
* @deprecated replaced by {@link com.sk89q.worldedit.function.pattern.RandomPattern}
* combined with {@link com.fastasyncworldedit.core.math.random.Linear2DRandom}.
*/
@Deprecated(forRemoval = true, since = "TODO")
public class Linear2DBlockPattern extends AbstractPattern {

private final Pattern[] patternsArray;
Expand Down
Expand Up @@ -9,6 +9,11 @@

import static java.lang.Math.floorDiv;

/**
* @deprecated replaced by {@link com.sk89q.worldedit.function.pattern.RandomPattern}
* combined with {@link com.fastasyncworldedit.core.math.random.Linear3DRandom}.
*/
@Deprecated(forRemoval = true, since = "TODO")
public class Linear3DBlockPattern extends AbstractPattern {

private final Pattern[] patternsArray;
Expand Down
@@ -0,0 +1,50 @@
package com.fastasyncworldedit.core.math.random;

import static com.fastasyncworldedit.core.math.random.Linear3DRandom.doubleDiv;
import static java.lang.Math.floorDiv;

/**
* A {@link SimpleRandom} that deterministically maps coordinates
* to values.
* @since TODO
*/
public class Linear2DRandom implements SimpleRandom {
private final int xScale;
private final int zScale;

/**
* Creates a new {@link Linear2DRandom} instance
*
* @param xScale the scale applied to the x component of a coordinate
* @param zScale the scale applied to the z component of a coordinate
*/
public Linear2DRandom(final int xScale, final int zScale) {
this.xScale = xScale;
this.zScale = zScale;
}

@Override
public double nextDouble(final int x, final int y, final int z) {
return nextDouble(x, y, z, 1d);
}

@Override
public double nextDouble(final int x, final int y, final int z, double bound) {
double index = (doubleDiv(x, this.xScale) + doubleDiv(z, this.zScale)) % bound;
if (index < 0) {
index += bound;
}
return index;

}

@Override
public int nextInt(final int x, final int y, final int z, final int bound) {
int index = (floorDiv(x, this.xScale) + floorDiv(z, this.zScale)) % bound;
if (index < 0) {
index += bound;
}
return index;
}

}
@@ -0,0 +1,58 @@
package com.fastasyncworldedit.core.math.random;

import static java.lang.Math.floorDiv;

/**
* A {@link SimpleRandom} that deterministically maps coordinates
* to values.
* @since TODO
*/
public class Linear3DRandom implements SimpleRandom {

private final int xScale;
private final int yScale;
private final int zScale;

/**
* Creates a new {@link Linear3DRandom} instance
*
* @param xScale the scale applied to the x component of a coordinate
* @param yScale the scale applied to the y component of a coordinate
* @param zScale the scale applied to the z component of a coordinate
*/
public Linear3DRandom(final int xScale, final int yScale, final int zScale) {
this.xScale = xScale;
this.yScale = yScale;
this.zScale = zScale;
}

@Override
public double nextDouble(final int x, final int y, final int z) {
return nextDouble(x, y, z, 1d);
}

@Override
public double nextDouble(final int x, final int y, final int z, double bound) {
double index = (doubleDiv(x, this.xScale) + doubleDiv(y, this.yScale) + doubleDiv(z, this.zScale)) % bound;
if (index < 0) {
index += bound;
}
return index;
}

// used to avoid explicit conversion at call site
static double doubleDiv(double dividend, double divisor) {
// add a minimal value to avoid too many integral values hitting the exact weight of an entry in SimpleRandomCollection
return Math.nextUp(dividend) / divisor;
}

@Override
public int nextInt(final int x, final int y, final int z, final int bound) {
int index = (floorDiv(x, this.xScale) + floorDiv(y, this.yScale) + floorDiv(z, this.zScale)) % bound;
if (index < 0) {
index += bound;
}
return index;
}

}
Expand Up @@ -13,6 +13,20 @@ public interface SimpleRandom {
*/
double nextDouble(int x, int y, int z);

/**
* Generate a random double from three integer components.
* The generated value is between 0 (inclusive) and {@code bound} (exclusive).
*
* @param x the first component
* @param y the second component
* @param z the third component
* @param bound upper bound (exclusive)
* @return a double between 0 (inclusive) and {@code bound} (exclusive)
*/
default double nextDouble(int x, int y, int z, double bound) {
return nextDouble(x, y, z) * bound;
}

/**
* Generate a random integer from three integer components.
* The generated value is between 0 (inclusive) and 1 (exclusive)
Expand All @@ -24,8 +38,8 @@ public interface SimpleRandom {
* @return a random integer between 0 (inclusive) and {@code bound} (exclusive)
*/
default int nextInt(int x, int y, int z, int bound) {
double val = nextDouble(x, y, z);
return (int) (val * bound);
double val = nextDouble(x, y, z, bound);
return (int) val;
}

}
Expand Up @@ -36,7 +36,7 @@ public void add(double weight, E result) {

@Override
public E next(int x, int y, int z) {
return map.ceilingEntry(getRandom().nextDouble(x, y, z) * this.total).getValue();
return map.ceilingEntry(getRandom().nextDouble(x, y, z, this.total)).getValue();
}

}