mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-22 08:19:19 +00:00
add back dfc
This commit is contained in:
@@ -327,106 +327,6 @@ index f28fbf81a417a678726d3f77b3999054676d522e..7ff32b1f93b31fafd13f4e0857d14d85
|
|||||||
Arrays.fill(this.keys, null);
|
Arrays.fill(this.keys, null);
|
||||||
Arrays.fill(this.byId, null);
|
Arrays.fill(this.byId, null);
|
||||||
this.nextId = 0;
|
this.nextId = 0;
|
||||||
diff --git a/net/minecraft/util/CubicSpline.java b/net/minecraft/util/CubicSpline.java
|
|
||||||
index f36f8f2d49d4eba5c80eb243883749d6f831eb8a..5abd899c88683cb79bb8f02e43c4bfbe8563f496 100644
|
|
||||||
--- a/net/minecraft/util/CubicSpline.java
|
|
||||||
+++ b/net/minecraft/util/CubicSpline.java
|
|
||||||
@@ -254,31 +254,47 @@ public interface CubicSpline<C, I extends ToFloatFunction<C>> extends ToFloatFun
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float apply(C object) {
|
|
||||||
- float f = this.coordinate.apply(object);
|
|
||||||
- int i = findIntervalStart(this.locations, f);
|
|
||||||
- int i1 = this.locations.length - 1;
|
|
||||||
- if (i < 0) {
|
|
||||||
- return linearExtend(f, this.locations, this.values.get(0).apply(object), this.derivatives, 0);
|
|
||||||
- } else if (i == i1) {
|
|
||||||
- return linearExtend(f, this.locations, this.values.get(i1).apply(object), this.derivatives, i1);
|
|
||||||
+ // DivineMC start - Some optimizations
|
|
||||||
+ float point = this.coordinate.apply(object);
|
|
||||||
+ int rangeForLocation = findIntervalStart(this.locations, point);
|
|
||||||
+ int last = this.locations.length - 1;
|
|
||||||
+ if (rangeForLocation < 0) {
|
|
||||||
+ return linearExtend(point, this.locations, this.values.get(0).apply(object), this.derivatives, 0);
|
|
||||||
+ } else if (rangeForLocation == last) {
|
|
||||||
+ return linearExtend(point, this.locations, this.values.get(last).apply(object), this.derivatives, last);
|
|
||||||
} else {
|
|
||||||
- float f1 = this.locations[i];
|
|
||||||
- float f2 = this.locations[i + 1];
|
|
||||||
- float f3 = (f - f1) / (f2 - f1);
|
|
||||||
- ToFloatFunction<C> toFloatFunction = (ToFloatFunction<C>)this.values.get(i);
|
|
||||||
- ToFloatFunction<C> toFloatFunction1 = (ToFloatFunction<C>)this.values.get(i + 1);
|
|
||||||
- float f4 = this.derivatives[i];
|
|
||||||
- float f5 = this.derivatives[i + 1];
|
|
||||||
- float f6 = toFloatFunction.apply(object);
|
|
||||||
- float f7 = toFloatFunction1.apply(object);
|
|
||||||
- float f8 = f4 * (f2 - f1) - (f7 - f6);
|
|
||||||
- float f9 = -f5 * (f2 - f1) + (f7 - f6);
|
|
||||||
- return Mth.lerp(f3, f6, f7) + f3 * (1.0F - f3) * Mth.lerp(f3, f8, f9);
|
|
||||||
+ float loc0 = this.locations[rangeForLocation];
|
|
||||||
+ float loc1 = this.locations[rangeForLocation + 1];
|
|
||||||
+ float locDist = loc1 - loc0;
|
|
||||||
+ float k = (point - loc0) / locDist;
|
|
||||||
+ float n = this.values.get(rangeForLocation).apply(object);
|
|
||||||
+ float o = this.values.get(rangeForLocation + 1).apply(object);
|
|
||||||
+ float onDist = o - n;
|
|
||||||
+ float p = this.derivatives[rangeForLocation] * locDist - onDist;
|
|
||||||
+ float q = -this.derivatives[rangeForLocation + 1] * locDist + onDist;
|
|
||||||
+ return Mth.lerp(k, n, o) + k * (1.0F - k) * Mth.lerp(k, p, q);
|
|
||||||
}
|
|
||||||
+ // DivineMC end - Some optimizations
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int findIntervalStart(float[] locations, float start) {
|
|
||||||
- return Mth.binarySearch(0, locations.length, i -> start < locations[i]) - 1;
|
|
||||||
+ // DivineMC start - Some optimizations
|
|
||||||
+ int min = 0;
|
|
||||||
+ int i = locations.length;
|
|
||||||
+
|
|
||||||
+ while (i > 0) {
|
|
||||||
+ int j = i / 2;
|
|
||||||
+ int k = min + j;
|
|
||||||
+ if (start < locations[k]) {
|
|
||||||
+ i = j;
|
|
||||||
+ } else {
|
|
||||||
+ min = k + 1;
|
|
||||||
+ i -= j + 1;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return min - 1;
|
|
||||||
+ // DivineMC end - Some optimizations
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
@@ -313,5 +329,27 @@ public interface CubicSpline<C, I extends ToFloatFunction<C>> extends ToFloatFun
|
|
||||||
this.derivatives
|
|
||||||
);
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ // DivineMC start - Some optimizations
|
|
||||||
+ @Override
|
|
||||||
+ public boolean equals(Object o) {
|
|
||||||
+ if (this == o) return true;
|
|
||||||
+ if (o == null || getClass() != o.getClass()) return false;
|
|
||||||
+ Multipoint<?, ?> that = (Multipoint<?, ?>) o;
|
|
||||||
+ return java.util.Objects.equals(coordinate, that.coordinate()) && java.util.Arrays.equals(locations, that.locations()) && java.util.Objects.equals(values, that.values()) && java.util.Arrays.equals(derivatives, that.derivatives());
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public int hashCode() {
|
|
||||||
+ int result = 1;
|
|
||||||
+
|
|
||||||
+ result = 31 * result + java.util.Objects.hashCode(coordinate);
|
|
||||||
+ result = 31 * result + java.util.Arrays.hashCode(locations);
|
|
||||||
+ result = 31 * result + java.util.Objects.hashCode(values);
|
|
||||||
+ result = 31 * result + java.util.Arrays.hashCode(derivatives);
|
|
||||||
+
|
|
||||||
+ return result;
|
|
||||||
+ }
|
|
||||||
+ // DivineMC end - Some optimizations
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diff --git a/net/minecraft/util/Mth.java b/net/minecraft/util/Mth.java
|
diff --git a/net/minecraft/util/Mth.java b/net/minecraft/util/Mth.java
|
||||||
index ab3a221c115992d0f4ea921aa92cf0976b815ff4..076a931341da486162f289a5f19d3d6736df7768 100644
|
index ab3a221c115992d0f4ea921aa92cf0976b815ff4..076a931341da486162f289a5f19d3d6736df7768 100644
|
||||||
--- a/net/minecraft/util/Mth.java
|
--- a/net/minecraft/util/Mth.java
|
||||||
@@ -665,7 +565,7 @@ index 6b50a3fc0476f4b9941f1e66fb3f2a79042e33aa..1fdbd88841993e377ea2e14b40d059dd
|
|||||||
int floor1 = Mth.floor(y);
|
int floor1 = Mth.floor(y);
|
||||||
int floor2 = Mth.floor(z);
|
int floor2 = Mth.floor(z);
|
||||||
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
||||||
index 5bcbebf35eb726a43b957aca5b8b7a1dca7648cd..d618752727e2f2f5c0c1afa97f455e349cb7e76c 100644
|
index a58133b53a19e90d4386f57891ee41a5c03228c2..a65c86b411c15bbdfd431dac00e510d2262e65e1 100644
|
||||||
--- a/net/minecraft/world/entity/Mob.java
|
--- a/net/minecraft/world/entity/Mob.java
|
||||||
+++ b/net/minecraft/world/entity/Mob.java
|
+++ b/net/minecraft/world/entity/Mob.java
|
||||||
@@ -698,7 +698,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
@@ -698,7 +698,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||||
@@ -698,7 +598,7 @@ index 5bcbebf35eb726a43b957aca5b8b7a1dca7648cd..d618752727e2f2f5c0c1afa97f455e34
|
|||||||
protected final void serverAiStep() {
|
protected final void serverAiStep() {
|
||||||
this.noActionTime++;
|
this.noActionTime++;
|
||||||
diff --git a/net/minecraft/world/level/GameRules.java b/net/minecraft/world/level/GameRules.java
|
diff --git a/net/minecraft/world/level/GameRules.java b/net/minecraft/world/level/GameRules.java
|
||||||
index 02bc5d83b92a594ec519f0a02b0517fdb4b9e954..86c1f5effde3173c8bc458af21b454c81738935e 100644
|
index 92fe6acbd530e985da23f50e615817309915122c..c9a2c4f7051639478bd9788911d3c6bead8f5152 100644
|
||||||
--- a/net/minecraft/world/level/GameRules.java
|
--- a/net/minecraft/world/level/GameRules.java
|
||||||
+++ b/net/minecraft/world/level/GameRules.java
|
+++ b/net/minecraft/world/level/GameRules.java
|
||||||
@@ -277,7 +277,7 @@ public class GameRules {
|
@@ -277,7 +277,7 @@ public class GameRules {
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ index f36f8f2d49d4eba5c80eb243883749d6f831eb8a..b43b7e242ea0a4f87704853c03201144
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
diff --git a/net/minecraft/world/level/levelgen/DensityFunctions.java b/net/minecraft/world/level/levelgen/DensityFunctions.java
|
diff --git a/net/minecraft/world/level/levelgen/DensityFunctions.java b/net/minecraft/world/level/levelgen/DensityFunctions.java
|
||||||
index 7178013421233d7dab36eb07a768907ce40e8745..f56321eefa5fcdfdb30883beaf97c87ac6fa0183 100644
|
index 4c53031cf8f6198825b190955d96f20bbcccd77e..8827b7525de30ce15fccb9ac9f073110ba6c7b50 100644
|
||||||
--- a/net/minecraft/world/level/levelgen/DensityFunctions.java
|
--- a/net/minecraft/world/level/levelgen/DensityFunctions.java
|
||||||
+++ b/net/minecraft/world/level/levelgen/DensityFunctions.java
|
+++ b/net/minecraft/world/level/levelgen/DensityFunctions.java
|
||||||
@@ -275,38 +275,66 @@ public final class DensityFunctions {
|
@@ -275,38 +275,66 @@ public final class DensityFunctions {
|
||||||
@@ -215,7 +215,7 @@ index 7178013421233d7dab36eb07a768907ce40e8745..f56321eefa5fcdfdb30883beaf97c87a
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -704,7 +732,105 @@ public final class DensityFunctions {
|
@@ -683,7 +711,105 @@ public final class DensityFunctions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +322,7 @@ index 7178013421233d7dab36eb07a768907ce40e8745..f56321eefa5fcdfdb30883beaf97c87a
|
|||||||
@Override
|
@Override
|
||||||
public double compute(DensityFunction.FunctionContext context) {
|
public double compute(DensityFunction.FunctionContext context) {
|
||||||
return this.wrapped.compute(context);
|
return this.wrapped.compute(context);
|
||||||
@@ -725,7 +851,19 @@ public final class DensityFunctions {
|
@@ -704,7 +830,19 @@ public final class DensityFunctions {
|
||||||
return this.wrapped.maxValue();
|
return this.wrapped.maxValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,9 +337,9 @@ index 7178013421233d7dab36eb07a768907ce40e8745..f56321eefa5fcdfdb30883beaf97c87a
|
|||||||
+ public DensityFunction wrapped() {
|
+ public DensityFunction wrapped() {
|
||||||
+ return wrapped;
|
+ return wrapped;
|
||||||
+ }
|
+ }
|
||||||
+
|
|
||||||
+ public static enum Type implements StringRepresentable { // - public
|
|
||||||
+ // DivineMC end - Density Function Compiler
|
+ // DivineMC end - Density Function Compiler
|
||||||
|
+
|
||||||
|
+ public static enum Type implements StringRepresentable { // DivineMC - Density Function Compiler - make this public
|
||||||
Interpolated("interpolated"),
|
Interpolated("interpolated"),
|
||||||
FlatCache("flat_cache"),
|
FlatCache("flat_cache"),
|
||||||
Cache2D("cache_2d"),
|
Cache2D("cache_2d"),
|
||||||
@@ -191,6 +191,7 @@ public class DivineConfig {
|
|||||||
public static boolean enableSecureSeed = false;
|
public static boolean enableSecureSeed = false;
|
||||||
public static boolean smoothBedrockLayer = false;
|
public static boolean smoothBedrockLayer = false;
|
||||||
public static boolean slopesVisualFix = false;
|
public static boolean slopesVisualFix = false;
|
||||||
|
public static boolean enableDensityFunctionCompiler = false;
|
||||||
public static boolean enableStructureLayoutOptimizer = true;
|
public static boolean enableStructureLayoutOptimizer = true;
|
||||||
public static boolean deduplicateShuffledTemplatePoolElementList = false;
|
public static boolean deduplicateShuffledTemplatePoolElementList = false;
|
||||||
private static void chunkSettings() {
|
private static void chunkSettings() {
|
||||||
@@ -238,6 +239,18 @@ public class DivineConfig {
|
|||||||
slopesVisualFix = getBoolean("settings.chunks.slopes-visual-fix", slopesVisualFix,
|
slopesVisualFix = getBoolean("settings.chunks.slopes-visual-fix", slopesVisualFix,
|
||||||
"Fixes MC-258859, fixing slopes visual bug in biomes like Snowy Slopes, Frozen Peaks, Jagged Peaks, and including Terralith.");
|
"Fixes MC-258859, fixing slopes visual bug in biomes like Snowy Slopes, Frozen Peaks, Jagged Peaks, and including Terralith.");
|
||||||
|
|
||||||
|
enableDensityFunctionCompiler = getBoolean("settings.chunk-generation.experimental.enable-density-function-compiler", enableDensityFunctionCompiler,
|
||||||
|
"Whether to use density function compiler to accelerate world generation",
|
||||||
|
"",
|
||||||
|
"Density function: https://minecraft.wiki/w/Density_function",
|
||||||
|
"",
|
||||||
|
"This functionality compiles density functions from world generation",
|
||||||
|
"datapacks (including vanilla generation) to JVM bytecode to increase",
|
||||||
|
"performance by allowing JVM JIT to better optimize the code.",
|
||||||
|
"All functions provided by vanilla are implemented.",
|
||||||
|
"",
|
||||||
|
"Please test if this optimization actually benefits your server, as",
|
||||||
|
"it can sometimes slow down chunk performance than speed it up.");
|
||||||
enableStructureLayoutOptimizer = getBoolean("settings.chunks.experimental.enable-structure-layout-optimizer", enableStructureLayoutOptimizer,
|
enableStructureLayoutOptimizer = getBoolean("settings.chunks.experimental.enable-structure-layout-optimizer", enableStructureLayoutOptimizer,
|
||||||
"Enables a port of the mod StructureLayoutOptimizer, which optimizes general Jigsaw structure generation");
|
"Enables a port of the mod StructureLayoutOptimizer, which optimizes general Jigsaw structure generation");
|
||||||
deduplicateShuffledTemplatePoolElementList = getBoolean("settings.chunks.experimental.deduplicate-shuffled-template-pool-element-list", deduplicateShuffledTemplatePoolElementList,
|
deduplicateShuffledTemplatePoolElementList = getBoolean("settings.chunks.experimental.deduplicate-shuffled-template-pool-element-list", deduplicateShuffledTemplatePoolElementList,
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.levelgen.NoiseRouterData;
|
||||||
|
|
||||||
|
public interface IDensityFunctionsCaveScaler {
|
||||||
|
static double invokeScaleCaves(double value) {
|
||||||
|
return NoiseRouterData.QuantizedSpaghettiRarity.getSphaghettiRarity2D(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static double invokeScaleTunnels(double value) {
|
||||||
|
return NoiseRouterData.QuantizedSpaghettiRarity.getSpaghettiRarity3D(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public interface AstNode {
|
||||||
|
double evalSingle(int var1, int var2, int var3, EvalType var4);
|
||||||
|
|
||||||
|
void evalMulti(double[] var1, int[] var2, int[] var3, int[] var4, EvalType var5);
|
||||||
|
|
||||||
|
AstNode[] getChildren();
|
||||||
|
|
||||||
|
AstNode transform(AstTransformer var1);
|
||||||
|
|
||||||
|
void doBytecodeGenSingle(BytecodeGen.Context var1, InstructionAdapter var2, BytecodeGen.Context.LocalVarConsumer var3);
|
||||||
|
|
||||||
|
void doBytecodeGenMulti(BytecodeGen.Context var1, InstructionAdapter var2, BytecodeGen.Context.LocalVarConsumer var3);
|
||||||
|
|
||||||
|
boolean relaxedEquals(AstNode var1);
|
||||||
|
|
||||||
|
int relaxedHashCode();
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast;
|
||||||
|
|
||||||
|
public interface AstTransformer {
|
||||||
|
AstNode transform(AstNode var1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.vif.EachApplierVanillaInterface;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import net.minecraft.world.level.levelgen.NoiseChunk;
|
||||||
|
|
||||||
|
public enum EvalType {
|
||||||
|
NORMAL,
|
||||||
|
INTERPOLATION;
|
||||||
|
|
||||||
|
private EvalType() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EvalType from(DensityFunction.FunctionContext pos) {
|
||||||
|
return pos instanceof NoiseChunk ? INTERPOLATION : NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static EvalType from(DensityFunction.ContextProvider applier) {
|
||||||
|
if (applier instanceof EachApplierVanillaInterface vif) {
|
||||||
|
return vif.getType();
|
||||||
|
} else {
|
||||||
|
return applier instanceof NoiseChunk ? INTERPOLATION : NORMAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.binary.AddNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.binary.MaxNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.binary.MaxShortNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.binary.MinNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.binary.MinShortNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.binary.MulNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.misc.CacheLikeNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.misc.ConstantNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.misc.DelegateNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.misc.RangeChoiceNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.misc.YClampedGradientNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.noise.DFTNoiseNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.noise.DFTShiftANode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.noise.DFTShiftBNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.noise.DFTShiftNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.noise.DFTWeirdScaledSamplerNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.noise.ShiftedNoiseNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.spline.SplineAstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.unary.AbsNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.unary.CubeNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.unary.NegMulNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.unary.SquareNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.unary.SqueezeNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ducks.IEqualityOverriding;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ducks.IFastCacheLike;
|
||||||
|
import org.bxteam.divinemc.dfc.common.vif.AstVanillaInterface;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunctions;
|
||||||
|
import net.minecraft.world.level.levelgen.NoiseChunk;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class McToAst {
|
||||||
|
public McToAst() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AstNode toAst(DensityFunction df) {
|
||||||
|
Objects.requireNonNull(df);
|
||||||
|
return switch (df) {
|
||||||
|
case AstVanillaInterface f -> f.getAstNode();
|
||||||
|
|
||||||
|
case NoiseChunk.BlendAlpha f -> new ConstantNode(1.0);
|
||||||
|
case NoiseChunk.BlendOffset f -> new ConstantNode(0.0);
|
||||||
|
case DensityFunctions.BlendAlpha f -> new ConstantNode(1.0);
|
||||||
|
case DensityFunctions.BlendOffset f -> new ConstantNode(0.0);
|
||||||
|
case DensityFunctions.TwoArgumentSimpleFunction f -> switch (f.type()) {
|
||||||
|
case ADD -> new AddNode(toAst(f.argument1()), toAst(f.argument2()));
|
||||||
|
case MUL -> new MulNode(toAst(f.argument1()), toAst(f.argument2()));
|
||||||
|
case MIN -> {
|
||||||
|
double rightMin = f.argument2().minValue();
|
||||||
|
if (f.argument1().minValue() < rightMin) {
|
||||||
|
yield new MinShortNode(toAst(f.argument1()), toAst(f.argument2()), rightMin);
|
||||||
|
} else {
|
||||||
|
yield new MinNode(toAst(f.argument1()), toAst(f.argument2()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case MAX -> {
|
||||||
|
double rightMax = f.argument2().maxValue();
|
||||||
|
if (f.argument1().maxValue() > rightMax) {
|
||||||
|
yield new MaxShortNode(toAst(f.argument1()), toAst(f.argument2()), rightMax);
|
||||||
|
} else {
|
||||||
|
yield new MaxNode(toAst(f.argument1()), toAst(f.argument2()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
case DensityFunctions.BlendDensity f -> toAst(f.input());
|
||||||
|
case DensityFunctions.Clamp f -> new MaxNode(new ConstantNode(f.minValue()), new MinNode(new ConstantNode(f.maxValue()), toAst(f.input())));
|
||||||
|
case DensityFunctions.Constant f -> new ConstantNode(f.value());
|
||||||
|
case DensityFunctions.HolderHolder f -> toAst(f.function().value());
|
||||||
|
case DensityFunctions.Mapped f -> switch (f.type()) {
|
||||||
|
case ABS -> new AbsNode(toAst(f.input()));
|
||||||
|
case SQUARE -> new SquareNode(toAst(f.input()));
|
||||||
|
case CUBE -> new CubeNode(toAst(f.input()));
|
||||||
|
case HALF_NEGATIVE -> new NegMulNode(toAst(f.input()), 0.5);
|
||||||
|
case QUARTER_NEGATIVE -> new NegMulNode(toAst(f.input()), 0.25);
|
||||||
|
case SQUEEZE -> new SqueezeNode(toAst(f.input()));
|
||||||
|
};
|
||||||
|
case DensityFunctions.RangeChoice f -> new RangeChoiceNode(toAst(f.input()), f.minInclusive(), f.maxExclusive(), toAst(f.whenInRange()), toAst(f.whenOutOfRange()));
|
||||||
|
case DensityFunctions.Marker f -> {
|
||||||
|
DensityFunctions.Marker wrapping = new DensityFunctions.Marker(f.type(), new AstVanillaInterface(toAst(f.wrapped()), null));
|
||||||
|
((IEqualityOverriding) (Object) wrapping).c2me$overrideEquality(wrapping);
|
||||||
|
yield new DelegateNode(wrapping);
|
||||||
|
}
|
||||||
|
case IFastCacheLike f -> new CacheLikeNode(f, toAst(f.c2me$getDelegate()));
|
||||||
|
case DensityFunctions.ShiftedNoise f -> new ShiftedNoiseNode(toAst(f.shiftX()), toAst(f.shiftY()), toAst(f.shiftZ()), f.xzScale(), f.yScale(), f.noise());
|
||||||
|
case DensityFunctions.Noise f -> new DFTNoiseNode(f.noise(), f.xzScale(), f.yScale());
|
||||||
|
case DensityFunctions.Shift f -> new DFTShiftNode(f.offsetNoise());
|
||||||
|
case DensityFunctions.ShiftA f -> new DFTShiftANode(f.offsetNoise());
|
||||||
|
case DensityFunctions.ShiftB f -> new DFTShiftBNode(f.offsetNoise());
|
||||||
|
case DensityFunctions.YClampedGradient f -> new YClampedGradientNode(f.fromY(), f.toY(), f.fromValue(), f.toValue());
|
||||||
|
case DensityFunctions.WeirdScaledSampler f -> new DFTWeirdScaledSamplerNode(toAst(f.input()), f.noise(), f.rarityValueMapper());
|
||||||
|
case DensityFunctions.Spline f -> new SplineAstNode(f.spline());
|
||||||
|
|
||||||
|
default -> {
|
||||||
|
// delegateStatistics.computeIfAbsent(df.getClass(), unused -> new LongAdder()).increment();;
|
||||||
|
yield new DelegateNode(df);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull DensityFunction wrapVanilla(DensityFunction densityFunction) {
|
||||||
|
return new AstVanillaInterface(toAst(densityFunction), densityFunction);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.binary;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context;
|
||||||
|
import org.bxteam.divinemc.dfc.common.util.ArrayCache;
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public abstract class AbstractBinaryNode implements AstNode {
|
||||||
|
protected final AstNode left;
|
||||||
|
protected final AstNode right;
|
||||||
|
|
||||||
|
public AbstractBinaryNode(AstNode left, AstNode right) {
|
||||||
|
this.left = (AstNode)Objects.requireNonNull(left);
|
||||||
|
this.right = (AstNode)Objects.requireNonNull(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[]{this.left, this.right};
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
AbstractBinaryNode that = (AbstractBinaryNode)o;
|
||||||
|
return Objects.equals(this.left, that.left) && Objects.equals(this.right, that.right);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + this.left.hashCode();
|
||||||
|
result = 31 * result + this.right.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
AbstractBinaryNode that = (AbstractBinaryNode)o;
|
||||||
|
return this.left.relaxedEquals(that.left) && this.right.relaxedEquals(that.right);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + this.left.relaxedHashCode();
|
||||||
|
result = 31 * result + this.right.relaxedHashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract AstNode newInstance(AstNode var1, AstNode var2);
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
AstNode left = this.left.transform(transformer);
|
||||||
|
AstNode right = this.right.transform(transformer);
|
||||||
|
return left == this.left && right == this.right ? transformer.transform(this) : transformer.transform(this.newInstance(left, right));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String leftMethod = context.newSingleMethod(this.left);
|
||||||
|
String rightMethod = context.newSingleMethod(this.right);
|
||||||
|
context.callDelegateSingle(m, leftMethod);
|
||||||
|
context.callDelegateSingle(m, rightMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String leftMethod = context.newMultiMethod(this.left);
|
||||||
|
String rightMethod = context.newMultiMethod(this.right);
|
||||||
|
int res1 = localVarConsumer.createLocalVariable("res1", Type.getDescriptor(double[].class));
|
||||||
|
m.load(6, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.arraylength();
|
||||||
|
m.iconst(0);
|
||||||
|
m.invokevirtual(Type.getInternalName(ArrayCache.class), "getDoubleArray", Type.getMethodDescriptor(Type.getType(double[].class), new Type[]{Type.INT_TYPE, Type.BOOLEAN_TYPE}), false);
|
||||||
|
m.store(res1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
context.callDelegateMulti(m, leftMethod);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(res1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(6, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(context.className, rightMethod, Context.MULTI_DESC, false);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
this.bytecodeGenMultiBody(m, idx, res1);
|
||||||
|
});
|
||||||
|
m.load(6, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(res1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(Type.getInternalName(ArrayCache.class), "recycle", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.getType(double[].class)}), false);
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void bytecodeGenMultiBody(InstructionAdapter var1, int var2, int var3);
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.binary;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class AddNode extends AbstractBinaryNode {
|
||||||
|
public AddNode(AstNode left, AstNode right) {
|
||||||
|
super(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AstNode newInstance(AstNode left, AstNode right) {
|
||||||
|
return new AddNode(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
return this.left.evalSingle(x, y, z, type) + this.right.evalSingle(x, y, z, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
double[] res1 = new double[res.length];
|
||||||
|
this.left.evalMulti(res, x, y, z, type);
|
||||||
|
this.right.evalMulti(res1, x, y, z, type);
|
||||||
|
|
||||||
|
for(int i = 0; i < res1.length; ++i) {
|
||||||
|
res[i] += res1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
super.doBytecodeGenSingle(context, m, localVarConsumer);
|
||||||
|
m.add(Type.DOUBLE_TYPE);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void bytecodeGenMultiBody(InstructionAdapter m, int idx, int res1) {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.load(res1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.add(Type.DOUBLE_TYPE);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.binary;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class MaxNode extends AbstractBinaryNode {
|
||||||
|
public MaxNode(AstNode left, AstNode right) {
|
||||||
|
super(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AstNode newInstance(AstNode left, AstNode right) {
|
||||||
|
return new MaxNode(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
return Math.max(this.left.evalSingle(x, y, z, type), this.right.evalSingle(x, y, z, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
double[] res1 = new double[res.length];
|
||||||
|
this.left.evalMulti(res, x, y, z, type);
|
||||||
|
this.right.evalMulti(res1, x, y, z, type);
|
||||||
|
|
||||||
|
for(int i = 0; i < res1.length; ++i) {
|
||||||
|
res[i] = Math.max(res[i], res1[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
super.doBytecodeGenSingle(context, m, localVarConsumer);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "max", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void bytecodeGenMultiBody(InstructionAdapter m, int idx, int res1) {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.load(res1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "max", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.binary;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context;
|
||||||
|
import org.objectweb.asm.Label;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class MaxShortNode extends AbstractBinaryNode {
|
||||||
|
private final double rightMax;
|
||||||
|
|
||||||
|
public MaxShortNode(AstNode left, AstNode right, double rightMax) {
|
||||||
|
super(left, right);
|
||||||
|
this.rightMax = rightMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AstNode newInstance(AstNode left, AstNode right) {
|
||||||
|
return new MaxShortNode(left, right, this.rightMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
double evaled = this.left.evalSingle(x, y, z, type);
|
||||||
|
return evaled >= this.rightMax ? evaled : Math.max(evaled, this.right.evalSingle(x, y, z, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
this.left.evalMulti(res, x, y, z, type);
|
||||||
|
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
res[i] = res[i] >= this.rightMax ? res[i] : Math.max(res[i], this.right.evalSingle(x[i], y[i], z[i], type));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String leftMethod = context.newSingleMethod(this.left);
|
||||||
|
String rightMethod = context.newSingleMethod(this.right);
|
||||||
|
Label minLabel = new Label();
|
||||||
|
context.callDelegateSingle(m, leftMethod);
|
||||||
|
m.dup2();
|
||||||
|
m.dconst(this.rightMax);
|
||||||
|
m.cmpl(Type.DOUBLE_TYPE);
|
||||||
|
m.iflt(minLabel);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
m.visitLabel(minLabel);
|
||||||
|
context.callDelegateSingle(m, rightMethod);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "max", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String leftMethod = context.newMultiMethod(this.left);
|
||||||
|
String rightMethodSingle = context.newSingleMethod(this.right);
|
||||||
|
context.callDelegateMulti(m, leftMethod);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
Label minLabel = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.dconst(this.rightMax);
|
||||||
|
m.cmpl(Type.DOUBLE_TYPE);
|
||||||
|
m.iflt(minLabel);
|
||||||
|
m.goTo(end);
|
||||||
|
m.visitLabel(minLabel);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(context.className, rightMethodSingle, Context.SINGLE_DESC, false);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "max", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
|
||||||
|
m.visitLabel(end);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void bytecodeGenMultiBody(InstructionAdapter m, int idx, int res1) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.binary;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class MinNode extends AbstractBinaryNode {
|
||||||
|
public MinNode(AstNode left, AstNode right) {
|
||||||
|
super(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AstNode newInstance(AstNode left, AstNode right) {
|
||||||
|
return new MinNode(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
return Math.min(this.left.evalSingle(x, y, z, type), this.right.evalSingle(x, y, z, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
double[] res1 = new double[res.length];
|
||||||
|
this.left.evalMulti(res, x, y, z, type);
|
||||||
|
this.right.evalMulti(res1, x, y, z, type);
|
||||||
|
|
||||||
|
for(int i = 0; i < res1.length; ++i) {
|
||||||
|
res[i] = Math.min(res[i], res1[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
super.doBytecodeGenSingle(context, m, localVarConsumer);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "min", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void bytecodeGenMultiBody(InstructionAdapter m, int idx, int res1) {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.load(res1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "min", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.binary;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context;
|
||||||
|
import org.objectweb.asm.Label;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class MinShortNode extends AbstractBinaryNode {
|
||||||
|
private final double rightMin;
|
||||||
|
|
||||||
|
public MinShortNode(AstNode left, AstNode right, double rightMin) {
|
||||||
|
super(left, right);
|
||||||
|
this.rightMin = rightMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AstNode newInstance(AstNode left, AstNode right) {
|
||||||
|
return new MinShortNode(left, right, this.rightMin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
double evaled = this.left.evalSingle(x, y, z, type);
|
||||||
|
return evaled <= this.rightMin ? evaled : Math.min(evaled, this.right.evalSingle(x, y, z, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
this.left.evalMulti(res, x, y, z, type);
|
||||||
|
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
res[i] = res[i] <= this.rightMin ? res[i] : Math.min(res[i], this.right.evalSingle(x[i], y[i], z[i], type));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String leftMethod = context.newSingleMethod(this.left);
|
||||||
|
String rightMethod = context.newSingleMethod(this.right);
|
||||||
|
Label minLabel = new Label();
|
||||||
|
context.callDelegateSingle(m, leftMethod);
|
||||||
|
m.dup2();
|
||||||
|
m.dconst(this.rightMin);
|
||||||
|
m.cmpg(Type.DOUBLE_TYPE);
|
||||||
|
m.ifgt(minLabel);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
m.visitLabel(minLabel);
|
||||||
|
context.callDelegateSingle(m, rightMethod);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "min", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String leftMethod = context.newMultiMethod(this.left);
|
||||||
|
String rightMethodSingle = context.newSingleMethod(this.right);
|
||||||
|
context.callDelegateMulti(m, leftMethod);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
Label minLabel = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.dconst(this.rightMin);
|
||||||
|
m.cmpg(Type.DOUBLE_TYPE);
|
||||||
|
m.ifgt(minLabel);
|
||||||
|
m.goTo(end);
|
||||||
|
m.visitLabel(minLabel);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(context.className, rightMethodSingle, Context.SINGLE_DESC, false);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "min", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
|
||||||
|
m.visitLabel(end);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void bytecodeGenMultiBody(InstructionAdapter m, int idx, int res1) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.binary;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context;
|
||||||
|
import org.objectweb.asm.Label;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class MulNode extends AbstractBinaryNode {
|
||||||
|
public MulNode(AstNode left, AstNode right) {
|
||||||
|
super(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AstNode newInstance(AstNode left, AstNode right) {
|
||||||
|
return new MulNode(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
double evaled = this.left.evalSingle(x, y, z, type);
|
||||||
|
return evaled == 0.0 ? 0.0 : evaled * this.right.evalSingle(x, y, z, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
this.left.evalMulti(res, x, y, z, type);
|
||||||
|
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
res[i] = res[i] == 0.0 ? 0.0 : res[i] * this.right.evalSingle(x[i], y[i], z[i], type);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String leftMethod = context.newSingleMethod(this.left);
|
||||||
|
String rightMethod = context.newSingleMethod(this.right);
|
||||||
|
Label notZero = new Label();
|
||||||
|
context.callDelegateSingle(m, leftMethod);
|
||||||
|
m.dup2();
|
||||||
|
m.dconst(0.0);
|
||||||
|
m.cmpl(Type.DOUBLE_TYPE);
|
||||||
|
m.ifne(notZero);
|
||||||
|
m.dconst(0.0);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
m.visitLabel(notZero);
|
||||||
|
context.callDelegateSingle(m, rightMethod);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String leftMethod = context.newMultiMethod(this.left);
|
||||||
|
String rightMethodSingle = context.newSingleMethod(this.right);
|
||||||
|
context.callDelegateMulti(m, leftMethod);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
Label minLabel = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.dconst(0.0);
|
||||||
|
m.cmpl(Type.DOUBLE_TYPE);
|
||||||
|
m.ifne(minLabel);
|
||||||
|
m.pop2();
|
||||||
|
m.dconst(0.0);
|
||||||
|
m.goTo(end);
|
||||||
|
m.visitLabel(minLabel);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(context.className, rightMethodSingle, Context.SINGLE_DESC, false);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.visitLabel(end);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void bytecodeGenMultiBody(InstructionAdapter m, int idx, int res1) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.dfvisitor;
|
||||||
|
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunctions;
|
||||||
|
import net.minecraft.world.level.levelgen.NoiseChunk;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class StripBlending implements DensityFunction.Visitor {
|
||||||
|
public static final StripBlending INSTANCE = new StripBlending();
|
||||||
|
|
||||||
|
private StripBlending() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull DensityFunction apply(@NotNull DensityFunction densityFunction) {
|
||||||
|
return switch (densityFunction) {
|
||||||
|
case NoiseChunk.BlendAlpha ignored -> DensityFunctions.constant(1.0);
|
||||||
|
case NoiseChunk.BlendOffset ignored -> DensityFunctions.constant(0.0);
|
||||||
|
case DensityFunctions.BlendAlpha ignored -> DensityFunctions.constant(1.0);
|
||||||
|
case DensityFunctions.BlendOffset ignored -> DensityFunctions.constant(0.0);
|
||||||
|
default -> densityFunction;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.misc;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ducks.IFastCacheLike;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.IMultiMethod;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.ISingleMethod;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.SubCompiledDensityFunction;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunctions;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.objectweb.asm.Handle;
|
||||||
|
import org.objectweb.asm.Label;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class CacheLikeNode implements AstNode {
|
||||||
|
private final IFastCacheLike cacheLike;
|
||||||
|
private final AstNode delegate;
|
||||||
|
|
||||||
|
public CacheLikeNode(IFastCacheLike cacheLike, AstNode delegate) {
|
||||||
|
this.cacheLike = cacheLike;
|
||||||
|
this.delegate = (AstNode)Objects.requireNonNull(delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
if (this.cacheLike == null) {
|
||||||
|
return this.delegate.evalSingle(x, y, z, type);
|
||||||
|
} else {
|
||||||
|
double cached = this.cacheLike.c2me$getCached(x, y, z, type);
|
||||||
|
if (Double.doubleToRawLongBits(cached) != 9222769054270909007L) {
|
||||||
|
return cached;
|
||||||
|
} else {
|
||||||
|
double eval = this.delegate.evalSingle(x, y, z, type);
|
||||||
|
this.cacheLike.c2me$cache(x, y, z, type, eval);
|
||||||
|
return eval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
if (this.cacheLike == null) {
|
||||||
|
this.delegate.evalMulti(res, x, y, z, type);
|
||||||
|
} else {
|
||||||
|
boolean cached = this.cacheLike.c2me$getCached(res, x, y, z, type);
|
||||||
|
if (!cached) {
|
||||||
|
this.delegate.evalMulti(res, x, y, z, type);
|
||||||
|
this.cacheLike.c2me$cache(res, x, y, z, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[]{this.delegate};
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
AstNode delegate = this.delegate.transform(transformer);
|
||||||
|
return this.delegate == delegate ? transformer.transform(this) : transformer.transform(new CacheLikeNode(this.cacheLike, delegate));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(@NotNull Context context, @NotNull InstructionAdapter m, Context.@NotNull LocalVarConsumer localVarConsumer) {
|
||||||
|
String delegateMethod = context.newSingleMethod(this.delegate);
|
||||||
|
String cacheLikeField = context.newField(IFastCacheLike.class, this.cacheLike);
|
||||||
|
this.genPostprocessingMethod(context, cacheLikeField);
|
||||||
|
int eval = localVarConsumer.createLocalVariable("eval", Type.DOUBLE_TYPE.getDescriptor());
|
||||||
|
Label cacheExists = new Label();
|
||||||
|
Label cacheMiss = new Label();
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, cacheLikeField, Type.getDescriptor(IFastCacheLike.class));
|
||||||
|
m.ifnonnull(cacheExists);
|
||||||
|
context.callDelegateSingle(m, delegateMethod);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
m.visitLabel(cacheExists);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, cacheLikeField, Type.getDescriptor(IFastCacheLike.class));
|
||||||
|
m.load(1, Type.INT_TYPE);
|
||||||
|
m.load(2, Type.INT_TYPE);
|
||||||
|
m.load(3, Type.INT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokeinterface(Type.getInternalName(IFastCacheLike.class), "c2me$getCached", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.INT_TYPE, Type.INT_TYPE, Type.INT_TYPE, Type.getType(EvalType.class)}));
|
||||||
|
m.dup2();
|
||||||
|
m.invokestatic(Type.getInternalName(Double.class), "doubleToRawLongBits", Type.getMethodDescriptor(Type.LONG_TYPE, new Type[]{Type.DOUBLE_TYPE}), false);
|
||||||
|
m.lconst(9222769054270909007L);
|
||||||
|
m.lcmp();
|
||||||
|
m.ifeq(cacheMiss);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
m.visitLabel(cacheMiss);
|
||||||
|
m.pop2();
|
||||||
|
context.callDelegateSingle(m, delegateMethod);
|
||||||
|
m.store(eval, Type.DOUBLE_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, cacheLikeField, Type.getDescriptor(IFastCacheLike.class));
|
||||||
|
m.load(1, Type.INT_TYPE);
|
||||||
|
m.load(2, Type.INT_TYPE);
|
||||||
|
m.load(3, Type.INT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(eval, Type.DOUBLE_TYPE);
|
||||||
|
m.invokeinterface(Type.getInternalName(IFastCacheLike.class), "c2me$cache", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.INT_TYPE, Type.INT_TYPE, Type.INT_TYPE, Type.getType(EvalType.class), Type.DOUBLE_TYPE}));
|
||||||
|
m.load(eval, Type.DOUBLE_TYPE);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(@NotNull Context context, @NotNull InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String delegateMethod = context.newMultiMethod(this.delegate);
|
||||||
|
String cacheLikeField = context.newField(IFastCacheLike.class, this.cacheLike);
|
||||||
|
this.genPostprocessingMethod(context, cacheLikeField);
|
||||||
|
Label cacheExists = new Label();
|
||||||
|
Label cacheMiss = new Label();
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, cacheLikeField, Type.getDescriptor(IFastCacheLike.class));
|
||||||
|
m.ifnonnull(cacheExists);
|
||||||
|
context.callDelegateMulti(m, delegateMethod);
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
m.visitLabel(cacheExists);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, cacheLikeField, Type.getDescriptor(IFastCacheLike.class));
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokeinterface(Type.getInternalName(IFastCacheLike.class), "c2me$getCached", Type.getMethodDescriptor(Type.BOOLEAN_TYPE, new Type[]{Type.getType(double[].class), Type.getType(int[].class), Type.getType(int[].class), Type.getType(int[].class), Type.getType(EvalType.class)}));
|
||||||
|
m.ifeq(cacheMiss);
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
m.visitLabel(cacheMiss);
|
||||||
|
context.callDelegateMulti(m, delegateMethod);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, cacheLikeField, Type.getDescriptor(IFastCacheLike.class));
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokeinterface(Type.getInternalName(IFastCacheLike.class), "c2me$cache", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.getType(double[].class), Type.getType(int[].class), Type.getType(int[].class), Type.getType(int[].class), Type.getType(EvalType.class)}));
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void genPostprocessingMethod(@NotNull Context context, String cacheLikeField) {
|
||||||
|
String methodName = String.format("postProcessing_%s", cacheLikeField);
|
||||||
|
String delegateSingle = context.newSingleMethod(this.delegate);
|
||||||
|
String delegateMulti = context.newMultiMethod(this.delegate);
|
||||||
|
context.genPostprocessingMethod(methodName, (m) -> {
|
||||||
|
Label cacheExists = new Label();
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, cacheLikeField, Type.getDescriptor(IFastCacheLike.class));
|
||||||
|
m.dup();
|
||||||
|
m.ifnonnull(cacheExists);
|
||||||
|
m.pop();
|
||||||
|
m.pop();
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
m.visitLabel(cacheExists);
|
||||||
|
m.anew(Type.getType(SubCompiledDensityFunction.class));
|
||||||
|
m.dup();
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokedynamic("evalSingle", Type.getMethodDescriptor(Type.getType(ISingleMethod.class), new Type[]{Type.getType(context.classDesc)}), new Handle(6, "java/lang/invoke/LambdaMetafactory", "metafactory", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", false), new Object[]{Type.getMethodType(Context.SINGLE_DESC), new Handle(5, context.className, delegateSingle, Context.SINGLE_DESC, false), Type.getMethodType(Context.SINGLE_DESC)});
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokedynamic("evalMulti", Type.getMethodDescriptor(Type.getType(IMultiMethod.class), new Type[]{Type.getType(context.classDesc)}), new Handle(6, "java/lang/invoke/LambdaMetafactory", "metafactory", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;", false), new Object[]{Type.getMethodType(Context.MULTI_DESC), new Handle(5, context.className, delegateMulti, Context.MULTI_DESC, false), Type.getMethodType(Context.MULTI_DESC)});
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, cacheLikeField, Type.getDescriptor(IFastCacheLike.class));
|
||||||
|
m.checkcast(Type.getType(DensityFunction.class));
|
||||||
|
m.invokespecial(Type.getInternalName(SubCompiledDensityFunction.class), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.getType(ISingleMethod.class), Type.getType(IMultiMethod.class), Type.getType(DensityFunction.class)}), false);
|
||||||
|
m.checkcast(Type.getType(DensityFunction.class));
|
||||||
|
m.invokeinterface(Type.getInternalName(IFastCacheLike.class), "c2me$withDelegate", Type.getMethodDescriptor(Type.getType(DensityFunction.class), new Type[]{Type.getType(DensityFunction.class)}));
|
||||||
|
m.putfield(context.className, cacheLikeField, Type.getDescriptor(IFastCacheLike.class));
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public IFastCacheLike getCacheLike() {
|
||||||
|
return this.cacheLike;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode getDelegate() {
|
||||||
|
return this.delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
CacheLikeNode that = (CacheLikeNode)o;
|
||||||
|
return equals(this.cacheLike, that.cacheLike) && Objects.equals(this.delegate, that.delegate);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean equals(IFastCacheLike a, IFastCacheLike b) {
|
||||||
|
if (a instanceof DensityFunctions.Marker wrappingA) {
|
||||||
|
if (b instanceof DensityFunctions.Marker wrappingB) {
|
||||||
|
return wrappingA.type() == wrappingB.type();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.equals(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + hashCode(this.cacheLike);
|
||||||
|
result = 31 * result + this.delegate.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int hashCode(IFastCacheLike o) {
|
||||||
|
if (o instanceof DensityFunctions.Marker wrapping) {
|
||||||
|
return wrapping.type().hashCode();
|
||||||
|
} else {
|
||||||
|
return o.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
CacheLikeNode that = (CacheLikeNode)o;
|
||||||
|
return relaxedEquals(this.cacheLike, that.cacheLike) && this.delegate.relaxedEquals(that.delegate);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean relaxedEquals(IFastCacheLike a, IFastCacheLike b) {
|
||||||
|
if (a instanceof DensityFunctions.Marker wrappingA) {
|
||||||
|
if (b instanceof DensityFunctions.Marker wrappingB) {
|
||||||
|
return wrappingA.type() == wrappingB.type();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.getClass() == b.getClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + relaxedHashCode(this.cacheLike);
|
||||||
|
result = 31 * result + this.delegate.relaxedHashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int relaxedHashCode(IFastCacheLike o) {
|
||||||
|
if (o instanceof DensityFunctions.Marker wrapping) {
|
||||||
|
return wrapping.type().hashCode();
|
||||||
|
} else {
|
||||||
|
return o.getClass().hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.misc;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class ConstantNode implements AstNode {
|
||||||
|
private final double value;
|
||||||
|
|
||||||
|
public ConstantNode(double value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
Arrays.fill(res, this.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
return transformer.transform(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
m.dconst(this.value);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.dconst(this.value);
|
||||||
|
m.invokestatic(Type.getInternalName(Arrays.class), "fill", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.getType(double[].class), Type.DOUBLE_TYPE}), false);
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getValue() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
ConstantNode that = (ConstantNode)o;
|
||||||
|
return Double.compare(this.value, that.value) == 0;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return Double.hashCode(this.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
return this.equals(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
return this.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.misc;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import org.bxteam.divinemc.dfc.common.util.ArrayCache;
|
||||||
|
import org.bxteam.divinemc.dfc.common.vif.EachApplierVanillaInterface;
|
||||||
|
import org.bxteam.divinemc.dfc.common.vif.NoisePosVanillaInterface;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import org.objectweb.asm.Label;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class DelegateNode implements AstNode {
|
||||||
|
private final DensityFunction densityFunction;
|
||||||
|
|
||||||
|
public DelegateNode(DensityFunction densityFunction) {
|
||||||
|
this.densityFunction = Objects.requireNonNull(densityFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
return this.densityFunction.compute(new NoisePosVanillaInterface(x, y, z, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
if (res.length == 1) {
|
||||||
|
res[0] = this.evalSingle(x[0], y[0], z[0], type);
|
||||||
|
} else {
|
||||||
|
this.densityFunction.fillArray(res, new EachApplierVanillaInterface(x, y, z, type));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
return transformer.transform(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String newField = context.newField(DensityFunction.class, this.densityFunction);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, newField, Type.getDescriptor(DensityFunction.class));
|
||||||
|
m.anew(Type.getType(NoisePosVanillaInterface.class));
|
||||||
|
m.dup();
|
||||||
|
m.load(1, Type.INT_TYPE);
|
||||||
|
m.load(2, Type.INT_TYPE);
|
||||||
|
m.load(3, Type.INT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokespecial(Type.getInternalName(NoisePosVanillaInterface.class), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, Type.INT_TYPE, Type.INT_TYPE, Type.getType(EvalType.class)), false);
|
||||||
|
m.invokeinterface(Type.getInternalName(DensityFunction.class), "compute", Type.getMethodDescriptor(Type.DOUBLE_TYPE, Type.getType(DensityFunction.FunctionContext.class)));
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String newField = context.newField(DensityFunction.class, this.densityFunction);
|
||||||
|
Label moreThanTwoLabel = new Label();
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.arraylength();
|
||||||
|
m.iconst(1);
|
||||||
|
m.ificmpgt(moreThanTwoLabel);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.iconst(0);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, newField, Type.getDescriptor(DensityFunction.class));
|
||||||
|
m.anew(Type.getType(NoisePosVanillaInterface.class));
|
||||||
|
m.dup();
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.iconst(0);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.iconst(0);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.iconst(0);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokespecial(Type.getInternalName(NoisePosVanillaInterface.class), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, Type.INT_TYPE, Type.INT_TYPE, Type.getType(EvalType.class)), false);
|
||||||
|
m.invokeinterface(Type.getInternalName(DensityFunction.class), "compute", Type.getMethodDescriptor(Type.DOUBLE_TYPE, Type.getType(DensityFunction.FunctionContext.class)));
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
m.visitLabel(moreThanTwoLabel);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, newField, Type.getDescriptor(DensityFunction.class));
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.anew(Type.getType(EachApplierVanillaInterface.class));
|
||||||
|
m.dup();
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(6, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokespecial(Type.getInternalName(EachApplierVanillaInterface.class), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(int[].class), Type.getType(int[].class), Type.getType(int[].class), Type.getType(EvalType.class), Type.getType(ArrayCache.class)), false);
|
||||||
|
m.invokeinterface(Type.getInternalName(DensityFunction.class), "fillArray", Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(double[].class), Type.getType(DensityFunction.ContextProvider.class)));
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DensityFunction getDelegate() {
|
||||||
|
return this.densityFunction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
DelegateNode that = (DelegateNode)o;
|
||||||
|
return Objects.equals(this.densityFunction, that.densityFunction);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + Objects.hashCode(this.getClass());
|
||||||
|
result = 31 * result + Objects.hashCode(this.densityFunction);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
DelegateNode that = (DelegateNode)o;
|
||||||
|
return this.densityFunction.getClass() == that.densityFunction.getClass();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + Objects.hashCode(this.getClass());
|
||||||
|
result = 31 * result + Objects.hashCode(this.densityFunction.getClass());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,337 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.misc;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context;
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.objectweb.asm.Label;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class RangeChoiceNode implements AstNode {
|
||||||
|
private final AstNode input;
|
||||||
|
private final double minInclusive;
|
||||||
|
private final double maxExclusive;
|
||||||
|
private final AstNode whenInRange;
|
||||||
|
private final AstNode whenOutOfRange;
|
||||||
|
|
||||||
|
public RangeChoiceNode(AstNode input, double minInclusive, double maxExclusive, AstNode whenInRange, AstNode whenOutOfRange) {
|
||||||
|
this.input = (AstNode)Objects.requireNonNull(input);
|
||||||
|
this.minInclusive = minInclusive;
|
||||||
|
this.maxExclusive = maxExclusive;
|
||||||
|
this.whenInRange = (AstNode)Objects.requireNonNull(whenInRange);
|
||||||
|
this.whenOutOfRange = (AstNode)Objects.requireNonNull(whenOutOfRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
double v = this.input.evalSingle(x, y, z, type);
|
||||||
|
return v >= this.minInclusive && v < this.maxExclusive ? this.whenInRange.evalSingle(x, y, z, type) : this.whenOutOfRange.evalSingle(x, y, z, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
this.input.evalMulti(res, x, y, z, type);
|
||||||
|
int numInRange = 0;
|
||||||
|
|
||||||
|
int numOutOfRange;
|
||||||
|
for(numOutOfRange = 0; numOutOfRange < x.length; ++numOutOfRange) {
|
||||||
|
double v = res[numOutOfRange];
|
||||||
|
if (v >= this.minInclusive && v < this.maxExclusive) {
|
||||||
|
++numInRange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numOutOfRange = res.length - numInRange;
|
||||||
|
if (numInRange == 0) {
|
||||||
|
this.evalChildMulti(this.whenOutOfRange, res, x, y, z, type);
|
||||||
|
} else if (numInRange == res.length) {
|
||||||
|
this.evalChildMulti(this.whenInRange, res, x, y, z, type);
|
||||||
|
} else {
|
||||||
|
int idx1 = 0;
|
||||||
|
int[] i1 = new int[numInRange];
|
||||||
|
double[] res1 = new double[numInRange];
|
||||||
|
int[] x1 = new int[numInRange];
|
||||||
|
int[] y1 = new int[numInRange];
|
||||||
|
int[] z1 = new int[numInRange];
|
||||||
|
int idx2 = 0;
|
||||||
|
int[] i2 = new int[numOutOfRange];
|
||||||
|
double[] res2 = new double[numOutOfRange];
|
||||||
|
int[] x2 = new int[numOutOfRange];
|
||||||
|
int[] y2 = new int[numOutOfRange];
|
||||||
|
int[] z2 = new int[numOutOfRange];
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < res.length; ++i) {
|
||||||
|
double v = res[i];
|
||||||
|
int index;
|
||||||
|
if (v >= this.minInclusive && v < this.maxExclusive) {
|
||||||
|
index = idx1++;
|
||||||
|
i1[index] = i;
|
||||||
|
x1[index] = x[i];
|
||||||
|
y1[index] = y[i];
|
||||||
|
z1[index] = z[i];
|
||||||
|
} else {
|
||||||
|
index = idx2++;
|
||||||
|
i2[index] = i;
|
||||||
|
x2[index] = x[i];
|
||||||
|
y2[index] = y[i];
|
||||||
|
z2[index] = z[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.evalChildMulti(this.whenInRange, res1, x1, y1, z1, type);
|
||||||
|
this.evalChildMulti(this.whenOutOfRange, res2, x2, y2, z2, type);
|
||||||
|
|
||||||
|
for(i = 0; i < numInRange; ++i) {
|
||||||
|
res[i1[i]] = res1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < numOutOfRange; ++i) {
|
||||||
|
res[i2[i]] = res2[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void evalMultiStatic(double[] res, int[] x, int[] y, int[] z, EvalType type, double minInclusive, double maxExclusive, BytecodeGen.EvalSingleInterface whenInRangeSingle, BytecodeGen.EvalSingleInterface whenOutOfRangeSingle, BytecodeGen.EvalMultiInterface inputMulti, BytecodeGen.EvalMultiInterface whenInRangeMulti, BytecodeGen.EvalMultiInterface whenOutOfRangeMulti) {
|
||||||
|
inputMulti.evalMulti(res, x, y, z, type);
|
||||||
|
int numInRange = 0;
|
||||||
|
|
||||||
|
int numOutOfRange;
|
||||||
|
for(numOutOfRange = 0; numOutOfRange < x.length; ++numOutOfRange) {
|
||||||
|
double v = res[numOutOfRange];
|
||||||
|
if (v >= minInclusive && v < maxExclusive) {
|
||||||
|
++numInRange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numOutOfRange = res.length - numInRange;
|
||||||
|
if (numInRange == 0) {
|
||||||
|
evalChildMulti(whenOutOfRangeSingle, whenOutOfRangeMulti, res, x, y, z, type);
|
||||||
|
} else if (numInRange == res.length) {
|
||||||
|
evalChildMulti(whenInRangeSingle, whenInRangeMulti, res, x, y, z, type);
|
||||||
|
} else {
|
||||||
|
int idx1 = 0;
|
||||||
|
int[] i1 = new int[numInRange];
|
||||||
|
double[] res1 = new double[numInRange];
|
||||||
|
int[] x1 = new int[numInRange];
|
||||||
|
int[] y1 = new int[numInRange];
|
||||||
|
int[] z1 = new int[numInRange];
|
||||||
|
int idx2 = 0;
|
||||||
|
int[] i2 = new int[numOutOfRange];
|
||||||
|
double[] res2 = new double[numOutOfRange];
|
||||||
|
int[] x2 = new int[numOutOfRange];
|
||||||
|
int[] y2 = new int[numOutOfRange];
|
||||||
|
int[] z2 = new int[numOutOfRange];
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < res.length; ++i) {
|
||||||
|
double v = res[i];
|
||||||
|
int index;
|
||||||
|
if (v >= minInclusive && v < maxExclusive) {
|
||||||
|
index = idx1++;
|
||||||
|
i1[index] = i;
|
||||||
|
x1[index] = x[i];
|
||||||
|
y1[index] = y[i];
|
||||||
|
z1[index] = z[i];
|
||||||
|
} else {
|
||||||
|
index = idx2++;
|
||||||
|
i2[index] = i;
|
||||||
|
x2[index] = x[i];
|
||||||
|
y2[index] = y[i];
|
||||||
|
z2[index] = z[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
evalChildMulti(whenInRangeSingle, whenInRangeMulti, res1, x1, y1, z1, type);
|
||||||
|
evalChildMulti(whenOutOfRangeSingle, whenOutOfRangeMulti, res2, x2, y2, z2, type);
|
||||||
|
|
||||||
|
for(i = 0; i < numInRange; ++i) {
|
||||||
|
res[i1[i]] = res1[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < numOutOfRange; ++i) {
|
||||||
|
res[i2[i]] = res2[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void evalChildMulti(BytecodeGen.EvalSingleInterface single, BytecodeGen.EvalMultiInterface multi, double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
if (res.length == 1) {
|
||||||
|
res[0] = single.evalSingle(x[0], y[0], z[0], type);
|
||||||
|
} else {
|
||||||
|
multi.evalMulti(res, x, y, z, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void evalChildMulti(AstNode child, double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
if (res.length == 1) {
|
||||||
|
res[0] = child.evalSingle(x[0], y[0], z[0], type);
|
||||||
|
} else {
|
||||||
|
child.evalMulti(res, x, y, z, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[]{this.input, this.whenInRange, this.whenOutOfRange};
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
AstNode input = this.input.transform(transformer);
|
||||||
|
AstNode whenInRange = this.whenInRange.transform(transformer);
|
||||||
|
AstNode whenOutOfRange = this.whenOutOfRange.transform(transformer);
|
||||||
|
return this.input == input && this.whenInRange == whenInRange && this.whenOutOfRange == whenOutOfRange ? transformer.transform(this) : transformer.transform(new RangeChoiceNode(input, this.minInclusive, this.maxExclusive, whenInRange, whenOutOfRange));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String inputMethod = context.newSingleMethod(this.input);
|
||||||
|
String whenInRangeMethod = context.newSingleMethod(this.whenInRange);
|
||||||
|
String whenOutOfRangeMethod = context.newSingleMethod(this.whenOutOfRange);
|
||||||
|
int inputValue = localVarConsumer.createLocalVariable("inputValue", Type.DOUBLE_TYPE.getDescriptor());
|
||||||
|
context.callDelegateSingle(m, inputMethod);
|
||||||
|
m.store(inputValue, Type.DOUBLE_TYPE);
|
||||||
|
Label whenOutOfRangeLabel = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
m.load(inputValue, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.minInclusive);
|
||||||
|
m.cmpl(Type.DOUBLE_TYPE);
|
||||||
|
m.iflt(whenOutOfRangeLabel);
|
||||||
|
m.load(inputValue, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.maxExclusive);
|
||||||
|
m.cmpg(Type.DOUBLE_TYPE);
|
||||||
|
m.ifge(whenOutOfRangeLabel);
|
||||||
|
if (whenInRangeMethod.equals(inputMethod)) {
|
||||||
|
m.load(inputValue, Type.DOUBLE_TYPE);
|
||||||
|
} else {
|
||||||
|
context.callDelegateSingle(m, whenInRangeMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.goTo(end);
|
||||||
|
m.visitLabel(whenOutOfRangeLabel);
|
||||||
|
if (whenOutOfRangeMethod.equals(inputMethod)) {
|
||||||
|
m.load(inputValue, Type.DOUBLE_TYPE);
|
||||||
|
} else {
|
||||||
|
context.callDelegateSingle(m, whenOutOfRangeMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.visitLabel(end);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String inputSingle = context.newSingleMethod(this.input);
|
||||||
|
String whenInRangeSingle = context.newSingleMethod(this.whenInRange);
|
||||||
|
String whenOutOfRangeSingle = context.newSingleMethod(this.whenOutOfRange);
|
||||||
|
String inputMulti = context.newMultiMethod(this.input);
|
||||||
|
context.callDelegateMulti(m, inputMulti);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
Label whenOutOfRangeLabel = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.minInclusive);
|
||||||
|
m.cmpl(Type.DOUBLE_TYPE);
|
||||||
|
m.iflt(whenOutOfRangeLabel);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.maxExclusive);
|
||||||
|
m.cmpg(Type.DOUBLE_TYPE);
|
||||||
|
m.ifge(whenOutOfRangeLabel);
|
||||||
|
if (whenInRangeSingle.equals(inputSingle)) {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
} else {
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(context.className, whenInRangeSingle, Context.SINGLE_DESC, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.goTo(end);
|
||||||
|
m.visitLabel(whenOutOfRangeLabel);
|
||||||
|
if (whenOutOfRangeSingle.equals(inputSingle)) {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
} else {
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(context.className, whenOutOfRangeSingle, Context.SINGLE_DESC, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.visitLabel(end);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
RangeChoiceNode that = (RangeChoiceNode)o;
|
||||||
|
return Double.compare(this.minInclusive, that.minInclusive) == 0 && Double.compare(this.maxExclusive, that.maxExclusive) == 0 && Objects.equals(this.input, that.input) && Objects.equals(this.whenInRange, that.whenInRange) && Objects.equals(this.whenOutOfRange, that.whenOutOfRange);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + this.input.hashCode();
|
||||||
|
result = 31 * result + Double.hashCode(this.minInclusive);
|
||||||
|
result = 31 * result + Double.hashCode(this.maxExclusive);
|
||||||
|
result = 31 * result + this.whenInRange.hashCode();
|
||||||
|
result = 31 * result + this.whenOutOfRange.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
RangeChoiceNode that = (RangeChoiceNode)o;
|
||||||
|
return Double.compare(this.minInclusive, that.minInclusive) == 0 && Double.compare(this.maxExclusive, that.maxExclusive) == 0 && this.input.relaxedEquals(that.input) && this.whenInRange.relaxedEquals(that.whenInRange) && this.whenOutOfRange.relaxedEquals(that.whenOutOfRange);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + this.input.relaxedHashCode();
|
||||||
|
result = 31 * result + Double.hashCode(this.minInclusive);
|
||||||
|
result = 31 * result + Double.hashCode(this.maxExclusive);
|
||||||
|
result = 31 * result + this.whenInRange.relaxedHashCode();
|
||||||
|
result = 31 * result + this.whenOutOfRange.relaxedHashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.misc;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class RootNode implements AstNode {
|
||||||
|
private final AstNode next;
|
||||||
|
|
||||||
|
public RootNode(AstNode next) {
|
||||||
|
this.next = (AstNode)Objects.requireNonNull(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
return this.next.evalSingle(x, y, z, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
this.next.evalMulti(res, x, y, z, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[]{this.next};
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
AstNode next = this.next.transform(transformer);
|
||||||
|
return next == this.next ? transformer.transform(this) : transformer.transform(new RootNode(next));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String nextMethod = context.newSingleMethod(this.next);
|
||||||
|
context.callDelegateSingle(m, nextMethod);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String nextMethod = context.newMultiMethod(this.next);
|
||||||
|
context.callDelegateMulti(m, nextMethod);
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
RootNode that = (RootNode)o;
|
||||||
|
return Objects.equals(this.next, that.next);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + this.next.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
RootNode that = (RootNode)o;
|
||||||
|
return this.next.relaxedEquals(that.next);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + this.next.relaxedHashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.misc;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class YClampedGradientNode implements AstNode {
|
||||||
|
private final double fromY;
|
||||||
|
private final double toY;
|
||||||
|
private final double fromValue;
|
||||||
|
private final double toValue;
|
||||||
|
|
||||||
|
public YClampedGradientNode(double fromY, double toY, double fromValue, double toValue) {
|
||||||
|
this.fromY = fromY;
|
||||||
|
this.toY = toY;
|
||||||
|
this.fromValue = fromValue;
|
||||||
|
this.toValue = toValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
return Mth.clampedMap((double)y, this.fromY, this.toY, this.fromValue, this.toValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
res[i] = Mth.clampedMap((double)y[i], this.fromY, this.toY, this.fromValue, this.toValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
return transformer.transform(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
m.load(2, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.fromY);
|
||||||
|
m.dconst(this.toY);
|
||||||
|
m.dconst(this.fromValue);
|
||||||
|
m.dconst(this.toValue);
|
||||||
|
m.invokestatic(Type.getInternalName(Mth.class), "clampedMap", "(DDDDD)D", false);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.fromY);
|
||||||
|
m.dconst(this.toY);
|
||||||
|
m.dconst(this.fromValue);
|
||||||
|
m.dconst(this.toValue);
|
||||||
|
m.invokestatic(Type.getInternalName(Mth.class), "clampedMap", "(DDDDD)D", false);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
YClampedGradientNode that = (YClampedGradientNode)o;
|
||||||
|
return Double.compare(this.fromY, that.fromY) == 0 && Double.compare(this.toY, that.toY) == 0 && Double.compare(this.fromValue, that.fromValue) == 0 && Double.compare(this.toValue, that.toValue) == 0;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + Double.hashCode(this.fromY);
|
||||||
|
result = 31 * result + Double.hashCode(this.toY);
|
||||||
|
result = 31 * result + Double.hashCode(this.fromValue);
|
||||||
|
result = 31 * result + Double.hashCode(this.toValue);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
return this.equals(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
return this.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,131 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.noise;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class DFTNoiseNode implements AstNode {
|
||||||
|
private final DensityFunction.NoiseHolder noise;
|
||||||
|
private final double xzScale;
|
||||||
|
private final double yScale;
|
||||||
|
|
||||||
|
public DFTNoiseNode(DensityFunction.NoiseHolder noise, double xzScale, double yScale) {
|
||||||
|
this.noise = (DensityFunction.NoiseHolder)Objects.requireNonNull(noise);
|
||||||
|
this.xzScale = xzScale;
|
||||||
|
this.yScale = yScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
return this.noise.getValue((double)x * this.xzScale, (double)y * this.yScale, (double)z * this.xzScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
res[i] = this.noise.getValue((double)x[i] * this.xzScale, (double)y[i] * this.yScale, (double)z[i] * this.xzScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
return transformer.transform(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String noiseField = context.newField(DensityFunction.NoiseHolder.class, this.noise);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, noiseField, Type.getDescriptor(DensityFunction.NoiseHolder.class));
|
||||||
|
m.load(1, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.xzScale);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.load(2, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.yScale);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.load(3, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.xzScale);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.invokevirtual(Type.getInternalName(DensityFunction.NoiseHolder.class), "getValue", "(DDD)D", false);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String noiseField = context.newField(DensityFunction.NoiseHolder.class, this.noise);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, noiseField, Type.getDescriptor(DensityFunction.NoiseHolder.class));
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.xzScale);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.yScale);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.xzScale);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.invokevirtual(Type.getInternalName(DensityFunction.NoiseHolder.class), "getValue", "(DDD)D", false);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
DFTNoiseNode that = (DFTNoiseNode)o;
|
||||||
|
return Double.compare(this.xzScale, that.xzScale) == 0 && Double.compare(this.yScale, that.yScale) == 0 && Objects.equals(this.noise, that.noise);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + this.noise.hashCode();
|
||||||
|
result = 31 * result + Double.hashCode(this.xzScale);
|
||||||
|
result = 31 * result + Double.hashCode(this.yScale);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
DFTNoiseNode that = (DFTNoiseNode)o;
|
||||||
|
return Double.compare(this.xzScale, that.xzScale) == 0 && Double.compare(this.yScale, that.yScale) == 0;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + Double.hashCode(this.xzScale);
|
||||||
|
result = 31 * result + Double.hashCode(this.yScale);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.noise;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class DFTShiftANode implements AstNode {
|
||||||
|
private final DensityFunction.NoiseHolder offsetNoise;
|
||||||
|
|
||||||
|
public DFTShiftANode(DensityFunction.NoiseHolder offsetNoise) {
|
||||||
|
this.offsetNoise = (DensityFunction.NoiseHolder)Objects.requireNonNull(offsetNoise);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
return this.offsetNoise.getValue((double)x * 0.25, 0.0, (double)z * 0.25) * 4.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
res[i] = this.offsetNoise.getValue((double)x[i] * 0.25, 0.0, (double)z[i] * 0.25) * 4.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
return transformer.transform(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String noiseField = context.newField(DensityFunction.NoiseHolder.class, this.offsetNoise);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, noiseField, Type.getDescriptor(DensityFunction.NoiseHolder.class));
|
||||||
|
m.load(1, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.0);
|
||||||
|
m.load(3, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.invokevirtual(Type.getInternalName(DensityFunction.NoiseHolder.class), "getValue", "(DDD)D", false);
|
||||||
|
m.dconst(4.0);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String noiseField = context.newField(DensityFunction.NoiseHolder.class, this.offsetNoise);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, noiseField, Type.getDescriptor(DensityFunction.NoiseHolder.class));
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.0);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.invokevirtual(Type.getInternalName(DensityFunction.NoiseHolder.class), "getValue", "(DDD)D", false);
|
||||||
|
m.dconst(4.0);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
DFTShiftANode that = (DFTShiftANode)o;
|
||||||
|
return Objects.equals(this.offsetNoise, that.offsetNoise);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
Object o = this.getClass();
|
||||||
|
result = 31 * result + o.hashCode();
|
||||||
|
result = 31 * result + this.offsetNoise.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return o != null && this.getClass() == o.getClass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
return this.getClass().hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.noise;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class DFTShiftBNode implements AstNode {
|
||||||
|
private final DensityFunction.NoiseHolder offsetNoise;
|
||||||
|
|
||||||
|
public DFTShiftBNode(DensityFunction.NoiseHolder offsetNoise) {
|
||||||
|
this.offsetNoise = (DensityFunction.NoiseHolder)Objects.requireNonNull(offsetNoise);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
return this.offsetNoise.getValue((double)z * 0.25, (double)x * 0.25, 0.0) * 4.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
res[i] = this.offsetNoise.getValue((double)z[i] * 0.25, (double)x[i] * 0.25, 0.0) * 4.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
return transformer.transform(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String noiseField = context.newField(DensityFunction.NoiseHolder.class, this.offsetNoise);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, noiseField, Type.getDescriptor(DensityFunction.NoiseHolder.class));
|
||||||
|
m.load(3, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.load(1, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.0);
|
||||||
|
m.invokevirtual(Type.getInternalName(DensityFunction.NoiseHolder.class), "getValue", "(DDD)D", false);
|
||||||
|
m.dconst(4.0);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String noiseField = context.newField(DensityFunction.NoiseHolder.class, this.offsetNoise);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, noiseField, Type.getDescriptor(DensityFunction.NoiseHolder.class));
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.0);
|
||||||
|
m.invokevirtual(Type.getInternalName(DensityFunction.NoiseHolder.class), "getValue", "(DDD)D", false);
|
||||||
|
m.dconst(4.0);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
DFTShiftBNode that = (DFTShiftBNode)o;
|
||||||
|
return Objects.equals(this.offsetNoise, that.offsetNoise);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
Object o = this.getClass();
|
||||||
|
result = 31 * result + o.hashCode();
|
||||||
|
result = 31 * result + this.offsetNoise.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return o != null && this.getClass() == o.getClass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
return this.getClass().hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.noise;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class DFTShiftNode implements AstNode {
|
||||||
|
private final DensityFunction.NoiseHolder offsetNoise;
|
||||||
|
|
||||||
|
public DFTShiftNode(DensityFunction.NoiseHolder offsetNoise) {
|
||||||
|
this.offsetNoise = (DensityFunction.NoiseHolder)Objects.requireNonNull(offsetNoise);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
return this.offsetNoise.getValue((double)x * 0.25, (double)y * 0.25, (double)z * 0.25) * 4.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
res[i] = this.offsetNoise.getValue((double)x[i] * 0.25, (double)y[i] * 0.25, (double)z[i] * 0.25) * 4.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
return transformer.transform(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String noiseField = context.newField(DensityFunction.NoiseHolder.class, this.offsetNoise);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, noiseField, Type.getDescriptor(DensityFunction.NoiseHolder.class));
|
||||||
|
m.load(1, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.load(2, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.load(3, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.invokevirtual(Type.getInternalName(DensityFunction.NoiseHolder.class), "getValue", "(DDD)D", false);
|
||||||
|
m.dconst(4.0);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String noiseField = context.newField(DensityFunction.NoiseHolder.class, this.offsetNoise);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, noiseField, Type.getDescriptor(DensityFunction.NoiseHolder.class));
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.25);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.invokevirtual(Type.getInternalName(DensityFunction.NoiseHolder.class), "getValue", "(DDD)D", false);
|
||||||
|
m.dconst(4.0);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
DFTShiftNode that = (DFTShiftNode)o;
|
||||||
|
return Objects.equals(this.offsetNoise, that.offsetNoise);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
Object o = this.getClass();
|
||||||
|
result = 31 * result + o.hashCode();
|
||||||
|
result = 31 * result + this.offsetNoise.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return o != null && this.getClass() == o.getClass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
return this.getClass().hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.noise;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.IDensityFunctionsCaveScaler;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunctions;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class DFTWeirdScaledSamplerNode implements AstNode {
|
||||||
|
private final AstNode input;
|
||||||
|
private final DensityFunction.NoiseHolder noise;
|
||||||
|
private final DensityFunctions.WeirdScaledSampler.RarityValueMapper mapper;
|
||||||
|
|
||||||
|
public DFTWeirdScaledSamplerNode(AstNode input, DensityFunction.NoiseHolder noise, DensityFunctions.WeirdScaledSampler.RarityValueMapper mapper) {
|
||||||
|
this.input = Objects.requireNonNull(input);
|
||||||
|
this.noise = Objects.requireNonNull(noise);
|
||||||
|
this.mapper = Objects.requireNonNull(mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
double v = this.input.evalSingle(x, y, z, type);
|
||||||
|
double d = (this.mapper.mapper).get(v);
|
||||||
|
return d * Math.abs(this.noise.getValue((double)x / d, (double)y / d, (double)z / d));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
this.input.evalMulti(res, x, y, z, type);
|
||||||
|
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
double d = (this.mapper.mapper).get(res[i]);
|
||||||
|
res[i] = d * Math.abs(this.noise.getValue((double)x[i] / d, (double)y[i] / d, (double)z[i] / d));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[]{this.input};
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
AstNode input = this.input.transform(transformer);
|
||||||
|
return input == this.input ? transformer.transform(this) : transformer.transform(new DFTWeirdScaledSamplerNode(input, this.noise, this.mapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.@NotNull Context context, InstructionAdapter m, BytecodeGen.Context.@NotNull LocalVarConsumer localVarConsumer) {
|
||||||
|
String inputMethod = context.newSingleMethod(this.input);
|
||||||
|
String noiseField = context.newField(DensityFunction.NoiseHolder.class, this.noise);
|
||||||
|
int scale = localVarConsumer.createLocalVariable("scale", Type.DOUBLE_TYPE.getDescriptor());
|
||||||
|
context.callDelegateSingle(m, inputMethod);
|
||||||
|
switch (this.mapper) {
|
||||||
|
case TYPE1 -> m.invokestatic(Type.getInternalName(IDensityFunctionsCaveScaler.class), "invokeScaleTunnels", Type.getMethodDescriptor(Type.DOUBLE_TYPE, Type.DOUBLE_TYPE), true);
|
||||||
|
case TYPE2 -> m.invokestatic(Type.getInternalName(IDensityFunctionsCaveScaler.class), "invokeScaleCaves", Type.getMethodDescriptor(Type.DOUBLE_TYPE, Type.DOUBLE_TYPE), true);
|
||||||
|
default -> throw new UnsupportedOperationException(String.format("Unknown mapper %s", this.mapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
m.store(scale, Type.DOUBLE_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, noiseField, Type.getDescriptor(DensityFunction.NoiseHolder.class));
|
||||||
|
m.load(1, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.load(scale, Type.DOUBLE_TYPE);
|
||||||
|
m.div(Type.DOUBLE_TYPE);
|
||||||
|
m.load(2, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.load(scale, Type.DOUBLE_TYPE);
|
||||||
|
m.div(Type.DOUBLE_TYPE);
|
||||||
|
m.load(3, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.load(scale, Type.DOUBLE_TYPE);
|
||||||
|
m.div(Type.DOUBLE_TYPE);
|
||||||
|
m.invokevirtual(Type.getInternalName(DensityFunction.NoiseHolder.class), "getValue", "(DDD)D", false);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "abs", "(D)D", false);
|
||||||
|
m.load(scale, Type.DOUBLE_TYPE);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String inputMethod = context.newMultiMethod(this.input);
|
||||||
|
String noiseField = context.newField(DensityFunction.NoiseHolder.class, this.noise);
|
||||||
|
context.callDelegateMulti(m, inputMethod);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
int scale = localVarConsumer.createLocalVariable("scale", Type.DOUBLE_TYPE.getDescriptor());
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
switch (this.mapper) {
|
||||||
|
case TYPE1 -> m.invokestatic(Type.getInternalName(IDensityFunctionsCaveScaler.class), "invokeScaleTunnels", Type.getMethodDescriptor(Type.DOUBLE_TYPE, Type.DOUBLE_TYPE), true);
|
||||||
|
case TYPE2 -> m.invokestatic(Type.getInternalName(IDensityFunctionsCaveScaler.class), "invokeScaleCaves", Type.getMethodDescriptor(Type.DOUBLE_TYPE, Type.DOUBLE_TYPE), true);
|
||||||
|
default -> throw new UnsupportedOperationException(String.format("Unknown mapper %s", this.mapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
m.store(scale, Type.DOUBLE_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, noiseField, Type.getDescriptor(DensityFunction.NoiseHolder.class));
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.load(scale, Type.DOUBLE_TYPE);
|
||||||
|
m.div(Type.DOUBLE_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.load(scale, Type.DOUBLE_TYPE);
|
||||||
|
m.div(Type.DOUBLE_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.load(scale, Type.DOUBLE_TYPE);
|
||||||
|
m.div(Type.DOUBLE_TYPE);
|
||||||
|
m.invokevirtual(Type.getInternalName(DensityFunction.NoiseHolder.class), "getValue", "(DDD)D", false);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "abs", "(D)D", false);
|
||||||
|
m.load(scale, Type.DOUBLE_TYPE);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
DFTWeirdScaledSamplerNode that = (DFTWeirdScaledSamplerNode)o;
|
||||||
|
return Objects.equals(this.input, that.input) && Objects.equals(this.noise, that.noise) && this.mapper == that.mapper;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + this.input.hashCode();
|
||||||
|
result = 31 * result + this.noise.hashCode();
|
||||||
|
result = 31 * result + this.mapper.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
DFTWeirdScaledSamplerNode that = (DFTWeirdScaledSamplerNode)o;
|
||||||
|
return this.input.relaxedEquals(that.input) && this.mapper == that.mapper;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + this.input.relaxedHashCode();
|
||||||
|
result = 31 * result + this.mapper.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.noise;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context;
|
||||||
|
import org.bxteam.divinemc.dfc.common.util.ArrayCache;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class ShiftedNoiseNode implements AstNode {
|
||||||
|
private final AstNode shiftX;
|
||||||
|
private final AstNode shiftY;
|
||||||
|
private final AstNode shiftZ;
|
||||||
|
private final double xzScale;
|
||||||
|
private final double yScale;
|
||||||
|
private final DensityFunction.NoiseHolder noise;
|
||||||
|
|
||||||
|
public ShiftedNoiseNode(AstNode shiftX, AstNode shiftY, AstNode shiftZ, double xzScale, double yScale, DensityFunction.NoiseHolder noise) {
|
||||||
|
this.shiftX = (AstNode)Objects.requireNonNull(shiftX);
|
||||||
|
this.shiftY = (AstNode)Objects.requireNonNull(shiftY);
|
||||||
|
this.shiftZ = (AstNode)Objects.requireNonNull(shiftZ);
|
||||||
|
this.xzScale = xzScale;
|
||||||
|
this.yScale = yScale;
|
||||||
|
this.noise = (DensityFunction.NoiseHolder)Objects.requireNonNull(noise);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
double d = (double)x * this.xzScale + this.shiftX.evalSingle(x, y, z, type);
|
||||||
|
double e = (double)y * this.yScale + this.shiftY.evalSingle(x, y, z, type);
|
||||||
|
double f = (double)z * this.xzScale + this.shiftZ.evalSingle(x, y, z, type);
|
||||||
|
return this.noise.getValue(d, e, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
double[] res1 = new double[res.length];
|
||||||
|
double[] res2 = new double[res.length];
|
||||||
|
this.shiftX.evalMulti(res, x, y, z, type);
|
||||||
|
this.shiftY.evalMulti(res1, x, y, z, type);
|
||||||
|
this.shiftZ.evalMulti(res2, x, y, z, type);
|
||||||
|
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
res[i] = this.noise.getValue((double)x[i] * this.xzScale + res[i], (double)y[i] * this.yScale + res1[i], (double)z[i] * this.xzScale + res2[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[]{this.shiftX, this.shiftY, this.shiftZ};
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
AstNode shiftX = this.shiftX.transform(transformer);
|
||||||
|
AstNode shiftY = this.shiftY.transform(transformer);
|
||||||
|
AstNode shiftZ = this.shiftZ.transform(transformer);
|
||||||
|
return shiftX == this.shiftX && shiftY == this.shiftY && shiftZ == this.shiftZ ? transformer.transform(this) : transformer.transform(new ShiftedNoiseNode(shiftX, shiftY, shiftZ, this.xzScale, this.yScale, this.noise));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String noiseField = context.newField(DensityFunction.NoiseHolder.class, this.noise);
|
||||||
|
String shiftXMethod = context.newSingleMethod(this.shiftX);
|
||||||
|
String shiftYMethod = context.newSingleMethod(this.shiftY);
|
||||||
|
String shiftZMethod = context.newSingleMethod(this.shiftZ);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, noiseField, Type.getDescriptor(DensityFunction.NoiseHolder.class));
|
||||||
|
m.load(1, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.xzScale);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
context.callDelegateSingle(m, shiftXMethod);
|
||||||
|
m.add(Type.DOUBLE_TYPE);
|
||||||
|
m.load(2, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.yScale);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
context.callDelegateSingle(m, shiftYMethod);
|
||||||
|
m.add(Type.DOUBLE_TYPE);
|
||||||
|
m.load(3, Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.xzScale);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
context.callDelegateSingle(m, shiftZMethod);
|
||||||
|
m.add(Type.DOUBLE_TYPE);
|
||||||
|
m.invokevirtual(Type.getInternalName(DensityFunction.NoiseHolder.class), "getValue", "(DDD)D", false);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String noiseField = context.newField(DensityFunction.NoiseHolder.class, this.noise);
|
||||||
|
String shiftXMethod = context.newMultiMethod(this.shiftX);
|
||||||
|
String shiftYMethod = context.newMultiMethod(this.shiftY);
|
||||||
|
String shiftZMethod = context.newMultiMethod(this.shiftZ);
|
||||||
|
int res1 = localVarConsumer.createLocalVariable("res1", Type.getDescriptor(double[].class));
|
||||||
|
int res2 = localVarConsumer.createLocalVariable("res2", Type.getDescriptor(double[].class));
|
||||||
|
m.load(6, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.arraylength();
|
||||||
|
m.iconst(0);
|
||||||
|
m.invokevirtual(Type.getInternalName(ArrayCache.class), "getDoubleArray", Type.getMethodDescriptor(Type.getType(double[].class), new Type[]{Type.INT_TYPE, Type.BOOLEAN_TYPE}), false);
|
||||||
|
m.store(res1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(6, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.arraylength();
|
||||||
|
m.iconst(0);
|
||||||
|
m.invokevirtual(Type.getInternalName(ArrayCache.class), "getDoubleArray", Type.getMethodDescriptor(Type.getType(double[].class), new Type[]{Type.INT_TYPE, Type.BOOLEAN_TYPE}), false);
|
||||||
|
m.store(res2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
context.callDelegateMulti(m, shiftXMethod);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(res1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(6, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(context.className, shiftYMethod, Context.MULTI_DESC, false);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(res2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(6, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(context.className, shiftZMethod, Context.MULTI_DESC, false);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, noiseField, Type.getDescriptor(DensityFunction.NoiseHolder.class));
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.xzScale);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.add(Type.DOUBLE_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.yScale);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.load(res1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.add(Type.DOUBLE_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.cast(Type.INT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.xzScale);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.load(res2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.add(Type.DOUBLE_TYPE);
|
||||||
|
m.invokevirtual(Type.getInternalName(DensityFunction.NoiseHolder.class), "getValue", "(DDD)D", false);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.load(6, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(res1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(Type.getInternalName(ArrayCache.class), "recycle", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.getType(double[].class)}), false);
|
||||||
|
m.load(6, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(res2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(Type.getInternalName(ArrayCache.class), "recycle", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.getType(double[].class)}), false);
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
ShiftedNoiseNode that = (ShiftedNoiseNode)o;
|
||||||
|
return Double.compare(this.xzScale, that.xzScale) == 0 && Double.compare(this.yScale, that.yScale) == 0 && Objects.equals(this.shiftX, that.shiftX) && Objects.equals(this.shiftY, that.shiftY) && Objects.equals(this.shiftZ, that.shiftZ) && Objects.equals(this.noise, that.noise);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.shiftX.hashCode();
|
||||||
|
result = 31 * result + this.shiftY.hashCode();
|
||||||
|
result = 31 * result + this.shiftZ.hashCode();
|
||||||
|
result = 31 * result + Double.hashCode(this.xzScale);
|
||||||
|
result = 31 * result + Double.hashCode(this.yScale);
|
||||||
|
result = 31 * result + this.noise.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
ShiftedNoiseNode that = (ShiftedNoiseNode)o;
|
||||||
|
return Double.compare(this.xzScale, that.xzScale) == 0 && Double.compare(this.yScale, that.yScale) == 0 && this.shiftX.relaxedEquals(that.shiftX) && this.shiftY.relaxedEquals(that.shiftY) && this.shiftZ.relaxedEquals(that.shiftZ);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.shiftX.relaxedHashCode();
|
||||||
|
result = 31 * result + this.shiftY.relaxedHashCode();
|
||||||
|
result = 31 * result + this.shiftZ.relaxedHashCode();
|
||||||
|
result = 31 * result + Double.hashCode(this.xzScale);
|
||||||
|
result = 31 * result + Double.hashCode(this.yScale);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,453 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.spline;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.McToAst;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import org.bxteam.divinemc.dfc.common.vif.NoisePosVanillaInterface;
|
||||||
|
import it.unimi.dsi.fastutil.Pair;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntObjectPair;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.util.CubicSpline;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunctions;
|
||||||
|
import org.bxteam.divinemc.util.Assertions;
|
||||||
|
import org.objectweb.asm.Label;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.AnalyzerAdapter;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class SplineAstNode implements AstNode {
|
||||||
|
public static final String SPLINE_METHOD_DESC;
|
||||||
|
private final CubicSpline<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> spline;
|
||||||
|
|
||||||
|
public SplineAstNode(CubicSpline<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> spline) {
|
||||||
|
this.spline = spline;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
return (double)this.spline.apply(new DensityFunctions.Spline.Point(new NoisePosVanillaInterface(x, y, z, type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
res[i] = this.evalSingle(x[i], y[i], z[i], type);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
return transformer.transform(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
ValuesMethodDef splineMethod = doBytecodeGenSpline(context, this.spline);
|
||||||
|
callSplineSingle(context, m, splineMethod);
|
||||||
|
m.cast(Type.FLOAT_TYPE, Type.DOUBLE_TYPE);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ValuesMethodDef doBytecodeGenSpline(BytecodeGen.Context context, CubicSpline<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> spline) {
|
||||||
|
String name = context.getCachedSplineMethod(spline);
|
||||||
|
if (name != null) {
|
||||||
|
return new ValuesMethodDef(false, name, 0.0F);
|
||||||
|
} else if (spline instanceof CubicSpline.Constant) {
|
||||||
|
CubicSpline.Constant<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> spline1 = (CubicSpline.Constant)spline;
|
||||||
|
return new ValuesMethodDef(true, (String)null, spline1.value());
|
||||||
|
} else {
|
||||||
|
name = context.nextMethodName("Spline");
|
||||||
|
InstructionAdapter m = new InstructionAdapter(new AnalyzerAdapter(context.className, 18, name, SPLINE_METHOD_DESC, context.classWriter.visitMethod(18, name, SPLINE_METHOD_DESC, (String)null, (String[])null)));
|
||||||
|
List<IntObjectPair<Pair<String, String>>> extraLocals = new ArrayList();
|
||||||
|
Label start = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
m.visitLabel(start);
|
||||||
|
BytecodeGen.Context.LocalVarConsumer localVarConsumer = (localName, localDesc) -> {
|
||||||
|
int ordinal = extraLocals.size() + 5;
|
||||||
|
extraLocals.add(IntObjectPair.of(ordinal, Pair.of(localName, localDesc)));
|
||||||
|
return ordinal;
|
||||||
|
};
|
||||||
|
if (spline instanceof CubicSpline.Multipoint) {
|
||||||
|
CubicSpline.Multipoint<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> impl = (CubicSpline.Multipoint)spline;
|
||||||
|
ValuesMethodDef[] valuesMethods = (ValuesMethodDef[])impl.values().stream().map((spline1x) -> {
|
||||||
|
return doBytecodeGenSpline(context, spline1x);
|
||||||
|
}).toArray((x$0) -> {
|
||||||
|
return new ValuesMethodDef[x$0];
|
||||||
|
});
|
||||||
|
String locations = context.newField(float[].class, impl.locations());
|
||||||
|
String derivatives = context.newField(float[].class, impl.derivatives());
|
||||||
|
int point = localVarConsumer.createLocalVariable("point", Type.FLOAT_TYPE.getDescriptor());
|
||||||
|
int rangeForLocation = localVarConsumer.createLocalVariable("rangeForLocation", Type.INT_TYPE.getDescriptor());
|
||||||
|
int lastConst = impl.locations().length - 1;
|
||||||
|
String locationFunction = context.newSingleMethod(McToAst.toAst((DensityFunction)((DensityFunctions.Spline.Coordinate)impl.coordinate()).function().value()));
|
||||||
|
context.callDelegateSingle(m, locationFunction);
|
||||||
|
m.cast(Type.DOUBLE_TYPE, Type.FLOAT_TYPE);
|
||||||
|
m.store(point, Type.FLOAT_TYPE);
|
||||||
|
if (valuesMethods.length == 1) {
|
||||||
|
m.load(point, Type.FLOAT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, locations, Type.getDescriptor(float[].class));
|
||||||
|
callSplineSingle(context, m, valuesMethods[0]);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, derivatives, Type.getDescriptor(float[].class));
|
||||||
|
m.iconst(0);
|
||||||
|
m.invokestatic(Type.getInternalName(SplineSupport.class), "sampleOutsideRange", Type.getMethodDescriptor(Type.FLOAT_TYPE, new Type[]{Type.FLOAT_TYPE, Type.getType(float[].class), Type.FLOAT_TYPE, Type.getType(float[].class), Type.INT_TYPE}), false);
|
||||||
|
m.areturn(Type.FLOAT_TYPE);
|
||||||
|
} else {
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, locations, Type.getDescriptor(float[].class));
|
||||||
|
m.load(point, Type.FLOAT_TYPE);
|
||||||
|
m.invokestatic(Type.getInternalName(SplineSupport.class), "findRangeForLocation", Type.getMethodDescriptor(Type.INT_TYPE, new Type[]{Type.getType(float[].class), Type.FLOAT_TYPE}), false);
|
||||||
|
m.store(rangeForLocation, Type.INT_TYPE);
|
||||||
|
Label label1 = new Label();
|
||||||
|
Label label2 = new Label();
|
||||||
|
m.load(rangeForLocation, Type.INT_TYPE);
|
||||||
|
m.ifge(label1);
|
||||||
|
m.load(point, Type.FLOAT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, locations, Type.getDescriptor(float[].class));
|
||||||
|
callSplineSingle(context, m, valuesMethods[0]);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, derivatives, Type.getDescriptor(float[].class));
|
||||||
|
m.iconst(0);
|
||||||
|
m.invokestatic(Type.getInternalName(SplineSupport.class), "sampleOutsideRange", Type.getMethodDescriptor(Type.FLOAT_TYPE, new Type[]{Type.FLOAT_TYPE, Type.getType(float[].class), Type.FLOAT_TYPE, Type.getType(float[].class), Type.INT_TYPE}), false);
|
||||||
|
m.areturn(Type.FLOAT_TYPE);
|
||||||
|
m.visitLabel(label1);
|
||||||
|
m.load(rangeForLocation, Type.INT_TYPE);
|
||||||
|
m.iconst(lastConst);
|
||||||
|
m.ificmpne(label2);
|
||||||
|
m.load(point, Type.FLOAT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, locations, Type.getDescriptor(float[].class));
|
||||||
|
callSplineSingle(context, m, valuesMethods[lastConst]);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, derivatives, Type.getDescriptor(float[].class));
|
||||||
|
m.iconst(lastConst);
|
||||||
|
m.invokestatic(Type.getInternalName(SplineSupport.class), "sampleOutsideRange", Type.getMethodDescriptor(Type.FLOAT_TYPE, new Type[]{Type.FLOAT_TYPE, Type.getType(float[].class), Type.FLOAT_TYPE, Type.getType(float[].class), Type.INT_TYPE}), false);
|
||||||
|
m.areturn(Type.FLOAT_TYPE);
|
||||||
|
m.visitLabel(label2);
|
||||||
|
int loc0 = localVarConsumer.createLocalVariable("loc0", Type.FLOAT_TYPE.getDescriptor());
|
||||||
|
int loc1 = localVarConsumer.createLocalVariable("loc1", Type.FLOAT_TYPE.getDescriptor());
|
||||||
|
int locDist = localVarConsumer.createLocalVariable("locDist", Type.FLOAT_TYPE.getDescriptor());
|
||||||
|
int k = localVarConsumer.createLocalVariable("k", Type.FLOAT_TYPE.getDescriptor());
|
||||||
|
int n = localVarConsumer.createLocalVariable("n", Type.FLOAT_TYPE.getDescriptor());
|
||||||
|
int o = localVarConsumer.createLocalVariable("o", Type.FLOAT_TYPE.getDescriptor());
|
||||||
|
int onDist = localVarConsumer.createLocalVariable("onDist", Type.FLOAT_TYPE.getDescriptor());
|
||||||
|
int p = localVarConsumer.createLocalVariable("p", Type.FLOAT_TYPE.getDescriptor());
|
||||||
|
int q = localVarConsumer.createLocalVariable("q", Type.FLOAT_TYPE.getDescriptor());
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, locations, Type.getDescriptor(float[].class));
|
||||||
|
m.load(rangeForLocation, Type.INT_TYPE);
|
||||||
|
m.aload(Type.FLOAT_TYPE);
|
||||||
|
m.store(loc0, Type.FLOAT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, locations, Type.getDescriptor(float[].class));
|
||||||
|
m.load(rangeForLocation, Type.INT_TYPE);
|
||||||
|
m.iconst(1);
|
||||||
|
m.add(Type.INT_TYPE);
|
||||||
|
m.aload(Type.FLOAT_TYPE);
|
||||||
|
m.store(loc1, Type.FLOAT_TYPE);
|
||||||
|
m.load(loc1, Type.FLOAT_TYPE);
|
||||||
|
m.load(loc0, Type.FLOAT_TYPE);
|
||||||
|
m.sub(Type.FLOAT_TYPE);
|
||||||
|
m.store(locDist, Type.FLOAT_TYPE);
|
||||||
|
m.load(point, Type.FLOAT_TYPE);
|
||||||
|
m.load(loc0, Type.FLOAT_TYPE);
|
||||||
|
m.sub(Type.FLOAT_TYPE);
|
||||||
|
m.load(locDist, Type.FLOAT_TYPE);
|
||||||
|
m.div(Type.FLOAT_TYPE);
|
||||||
|
m.store(k, Type.FLOAT_TYPE);
|
||||||
|
Label[] jumpLabels = new Label[valuesMethods.length - 1];
|
||||||
|
boolean[] jumpGenerated = new boolean[valuesMethods.length - 1];
|
||||||
|
|
||||||
|
for(int i = 0; i < valuesMethods.length - 1; ++i) {
|
||||||
|
jumpLabels[i] = new Label();
|
||||||
|
}
|
||||||
|
|
||||||
|
Label defaultLabel = new Label();
|
||||||
|
Label label3 = new Label();
|
||||||
|
m.load(rangeForLocation, Type.INT_TYPE);
|
||||||
|
m.tableswitch(0, valuesMethods.length - 2, defaultLabel, jumpLabels);
|
||||||
|
|
||||||
|
for(int i = 0; i < valuesMethods.length - 1; ++i) {
|
||||||
|
if (!jumpGenerated[i]) {
|
||||||
|
m.visitLabel(jumpLabels[i]);
|
||||||
|
jumpGenerated[i] = true;
|
||||||
|
|
||||||
|
for(int j = i + 1; j < valuesMethods.length - 1; ++j) {
|
||||||
|
if (valuesMethods[i].equals(valuesMethods[j]) && valuesMethods[i + 1].equals(valuesMethods[j + 1])) {
|
||||||
|
m.visitLabel(jumpLabels[j]);
|
||||||
|
jumpGenerated[j] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callSplineSingle(context, m, valuesMethods[i]);
|
||||||
|
if (valuesMethods[i].equals(valuesMethods[i + 1])) {
|
||||||
|
m.dup();
|
||||||
|
m.store(n, Type.FLOAT_TYPE);
|
||||||
|
m.store(o, Type.FLOAT_TYPE);
|
||||||
|
} else {
|
||||||
|
m.store(n, Type.FLOAT_TYPE);
|
||||||
|
callSplineSingle(context, m, valuesMethods[i + 1]);
|
||||||
|
m.store(o, Type.FLOAT_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.goTo(label3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.visitLabel(defaultLabel);
|
||||||
|
m.iconst(0);
|
||||||
|
m.aconst("boom");
|
||||||
|
m.invokestatic(Type.getInternalName(Assertions.class), "assertTrue", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.BOOLEAN_TYPE, Type.getType(String.class)}), false);
|
||||||
|
m.fconst(Float.NaN);
|
||||||
|
m.areturn(Type.FLOAT_TYPE);
|
||||||
|
m.visitLabel(label3);
|
||||||
|
m.load(o, Type.FLOAT_TYPE);
|
||||||
|
m.load(n, Type.FLOAT_TYPE);
|
||||||
|
m.sub(Type.FLOAT_TYPE);
|
||||||
|
m.store(onDist, Type.FLOAT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, derivatives, Type.getDescriptor(float[].class));
|
||||||
|
m.load(rangeForLocation, Type.INT_TYPE);
|
||||||
|
m.aload(Type.FLOAT_TYPE);
|
||||||
|
m.load(locDist, Type.FLOAT_TYPE);
|
||||||
|
m.mul(Type.FLOAT_TYPE);
|
||||||
|
m.load(onDist, Type.FLOAT_TYPE);
|
||||||
|
m.sub(Type.FLOAT_TYPE);
|
||||||
|
m.store(p, Type.FLOAT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, derivatives, Type.getDescriptor(float[].class));
|
||||||
|
m.load(rangeForLocation, Type.INT_TYPE);
|
||||||
|
m.iconst(1);
|
||||||
|
m.add(Type.INT_TYPE);
|
||||||
|
m.aload(Type.FLOAT_TYPE);
|
||||||
|
m.neg(Type.FLOAT_TYPE);
|
||||||
|
m.load(locDist, Type.FLOAT_TYPE);
|
||||||
|
m.mul(Type.FLOAT_TYPE);
|
||||||
|
m.load(onDist, Type.FLOAT_TYPE);
|
||||||
|
m.add(Type.FLOAT_TYPE);
|
||||||
|
m.store(q, Type.FLOAT_TYPE);
|
||||||
|
m.load(k, Type.FLOAT_TYPE);
|
||||||
|
m.load(n, Type.FLOAT_TYPE);
|
||||||
|
m.load(o, Type.FLOAT_TYPE);
|
||||||
|
m.invokestatic(Type.getInternalName(Mth.class), "lerp", "(FFF)F", false);
|
||||||
|
m.load(k, Type.FLOAT_TYPE);
|
||||||
|
m.fconst(1.0F);
|
||||||
|
m.load(k, Type.FLOAT_TYPE);
|
||||||
|
m.sub(Type.FLOAT_TYPE);
|
||||||
|
m.mul(Type.FLOAT_TYPE);
|
||||||
|
m.load(k, Type.FLOAT_TYPE);
|
||||||
|
m.load(p, Type.FLOAT_TYPE);
|
||||||
|
m.load(q, Type.FLOAT_TYPE);
|
||||||
|
m.invokestatic(Type.getInternalName(Mth.class), "lerp", "(FFF)F", false);
|
||||||
|
m.mul(Type.FLOAT_TYPE);
|
||||||
|
m.add(Type.FLOAT_TYPE);
|
||||||
|
m.areturn(Type.FLOAT_TYPE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!(spline instanceof CubicSpline.Constant)) {
|
||||||
|
throw new UnsupportedOperationException(String.format("Unsupported spline implementation: %s", spline.getClass().getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
CubicSpline.Constant<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> floatFunction = (CubicSpline.Constant)spline;
|
||||||
|
m.fconst(floatFunction.value());
|
||||||
|
m.areturn(Type.FLOAT_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.visitLabel(end);
|
||||||
|
m.visitLocalVariable("this", context.classDesc, (String)null, start, end, 0);
|
||||||
|
m.visitLocalVariable("x", Type.INT_TYPE.getDescriptor(), (String)null, start, end, 1);
|
||||||
|
m.visitLocalVariable("y", Type.INT_TYPE.getDescriptor(), (String)null, start, end, 2);
|
||||||
|
m.visitLocalVariable("z", Type.INT_TYPE.getDescriptor(), (String)null, start, end, 3);
|
||||||
|
m.visitLocalVariable("evalType", Type.getType(EvalType.class).getDescriptor(), (String)null, start, end, 4);
|
||||||
|
Iterator var35 = extraLocals.iterator();
|
||||||
|
|
||||||
|
while(var35.hasNext()) {
|
||||||
|
IntObjectPair<Pair<String, String>> local = (IntObjectPair)var35.next();
|
||||||
|
m.visitLocalVariable((String)((Pair)local.right()).left(), (String)((Pair)local.right()).right(), (String)null, start, end, local.leftInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
m.visitMaxs(0, 0);
|
||||||
|
context.cacheSplineMethod(spline, name);
|
||||||
|
return new ValuesMethodDef(false, name, 0.0F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void callSplineSingle(BytecodeGen.Context context, InstructionAdapter m, ValuesMethodDef target) {
|
||||||
|
if (target.isConst()) {
|
||||||
|
m.fconst(target.constValue());
|
||||||
|
} else {
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(1, Type.INT_TYPE);
|
||||||
|
m.load(2, Type.INT_TYPE);
|
||||||
|
m.load(3, Type.INT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(context.className, target.generatedMethod(), SPLINE_METHOD_DESC, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
context.delegateToSingle(m, localVarConsumer, this);
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean deepEquals(CubicSpline<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> a, CubicSpline<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> b) {
|
||||||
|
if (a instanceof CubicSpline.Constant<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> a1) {
|
||||||
|
if (b instanceof CubicSpline.Constant<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> b1) {
|
||||||
|
return a1.value() == b1.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a instanceof CubicSpline.Multipoint<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> a1) {
|
||||||
|
if (b instanceof CubicSpline.Multipoint<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> b1) {
|
||||||
|
boolean equals1 = Arrays.equals(a1.derivatives(), b1.derivatives()) && Arrays.equals(a1.locations(), b1.locations()) && a1.values().size() == b1.values().size() && McToAst.toAst((DensityFunction)((DensityFunctions.Spline.Coordinate)a1.coordinate()).function().value()).equals(McToAst.toAst((DensityFunction)((DensityFunctions.Spline.Coordinate)b1.coordinate()).function().value()));
|
||||||
|
if (!equals1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = a1.values().size();
|
||||||
|
|
||||||
|
for(int i = 0; i < size; ++i) {
|
||||||
|
if (!deepEquals((CubicSpline)a1.values().get(i), (CubicSpline)b1.values().get(i))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean deepRelaxedEquals(CubicSpline<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> a, CubicSpline<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> b) {
|
||||||
|
if (a instanceof CubicSpline.Constant<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> a1) {
|
||||||
|
if (b instanceof CubicSpline.Constant<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> b1) {
|
||||||
|
return a1.value() == b1.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a instanceof CubicSpline.Multipoint<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> a1) {
|
||||||
|
if (b instanceof CubicSpline.Multipoint<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> b1) {
|
||||||
|
boolean equals1 = a1.values().size() == b1.values().size() && McToAst.toAst((DensityFunction)((DensityFunctions.Spline.Coordinate)a1.coordinate()).function().value()).relaxedEquals(McToAst.toAst((DensityFunction)((DensityFunctions.Spline.Coordinate)b1.coordinate()).function().value()));
|
||||||
|
if (!equals1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = a1.values().size();
|
||||||
|
|
||||||
|
for(int i = 0; i < size; ++i) {
|
||||||
|
if (!deepRelaxedEquals((CubicSpline)a1.values().get(i), (CubicSpline)b1.values().get(i))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int deepHashcode(CubicSpline<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> a) {
|
||||||
|
if (a instanceof CubicSpline.Constant<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> a1) {
|
||||||
|
return Float.hashCode(a1.value());
|
||||||
|
} else if (!(a instanceof CubicSpline.Multipoint<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> a1)) {
|
||||||
|
return a.hashCode();
|
||||||
|
} else {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + Arrays.hashCode(a1.derivatives());
|
||||||
|
result = 31 * result + Arrays.hashCode(a1.locations());
|
||||||
|
|
||||||
|
CubicSpline spline;
|
||||||
|
for(Iterator var4 = a1.values().iterator(); var4.hasNext(); result = 31 * result + deepHashcode(spline)) {
|
||||||
|
spline = (CubicSpline)var4.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
result = 31 * result + McToAst.toAst((DensityFunction)((DensityFunctions.Spline.Coordinate)a1.coordinate()).function().value()).hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int deepRelaxedHashcode(CubicSpline<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> a) {
|
||||||
|
if (a instanceof CubicSpline.Constant<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> a1) {
|
||||||
|
return Float.hashCode(a1.value());
|
||||||
|
} else if (!(a instanceof CubicSpline.Multipoint<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> a1)) {
|
||||||
|
return a.hashCode();
|
||||||
|
} else {
|
||||||
|
int result = 1;
|
||||||
|
|
||||||
|
CubicSpline spline;
|
||||||
|
for(Iterator var4 = a1.values().iterator(); var4.hasNext(); result = 31 * result + deepRelaxedHashcode(spline)) {
|
||||||
|
spline = (CubicSpline)var4.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
result = 31 * result + McToAst.toAst((DensityFunction)((DensityFunctions.Spline.Coordinate)a1.coordinate()).function().value()).relaxedHashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
SplineAstNode that = (SplineAstNode)o;
|
||||||
|
return deepEquals(this.spline, that.spline);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return deepHashcode(this.spline);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
SplineAstNode that = (SplineAstNode)o;
|
||||||
|
return deepRelaxedEquals(this.spline, that.spline);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
return deepRelaxedHashcode(this.spline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
SPLINE_METHOD_DESC = Type.getMethodDescriptor(Type.getType(Float.TYPE), new Type[]{Type.getType(Integer.TYPE), Type.getType(Integer.TYPE), Type.getType(Integer.TYPE), Type.getType(EvalType.class)});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static record ValuesMethodDef(boolean isConst, String generatedMethod, float constValue) {
|
||||||
|
private ValuesMethodDef(boolean isConst, String generatedMethod, float constValue) {
|
||||||
|
this.isConst = isConst;
|
||||||
|
this.generatedMethod = generatedMethod;
|
||||||
|
this.constValue = constValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConst() {
|
||||||
|
return this.isConst;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String generatedMethod() {
|
||||||
|
return this.generatedMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float constValue() {
|
||||||
|
return this.constValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.spline;
|
||||||
|
|
||||||
|
public class SplineSupport {
|
||||||
|
public SplineSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int findRangeForLocation(float[] locations, float x) {
|
||||||
|
int min = 0;
|
||||||
|
int i = locations.length;
|
||||||
|
|
||||||
|
while(i > 0) {
|
||||||
|
int j = i / 2;
|
||||||
|
int k = min + j;
|
||||||
|
if (x < locations[k]) {
|
||||||
|
i = j;
|
||||||
|
} else {
|
||||||
|
min = k + 1;
|
||||||
|
i -= j + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return min - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float sampleOutsideRange(float point, float[] locations, float value, float[] derivatives, int i) {
|
||||||
|
float f = derivatives[i];
|
||||||
|
return f == 0.0F ? value : value + f * (point - locations[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.unary;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class AbsNode extends AbstractUnaryNode {
|
||||||
|
public AbsNode(AstNode operand) {
|
||||||
|
super(operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AstNode newInstance(AstNode operand) {
|
||||||
|
return new AbsNode(operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
return Math.abs(this.operand.evalSingle(x, y, z, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
this.operand.evalMulti(res, x, y, z, type);
|
||||||
|
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
res[i] = Math.abs(res[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
super.doBytecodeGenSingle(context, m, localVarConsumer);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "abs", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE}), false);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
super.doBytecodeGenMulti(context, m, localVarConsumer);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "abs", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE}), false);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.unary;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public abstract class AbstractUnaryNode implements AstNode {
|
||||||
|
protected final AstNode operand;
|
||||||
|
|
||||||
|
public AbstractUnaryNode(AstNode operand) {
|
||||||
|
this.operand = (AstNode)Objects.requireNonNull(operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode[] getChildren() {
|
||||||
|
return new AstNode[]{this.operand};
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
AbstractUnaryNode that = (AbstractUnaryNode)o;
|
||||||
|
return Objects.equals(this.operand, that.operand);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + this.operand.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean relaxedEquals(AstNode o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
} else if (o != null && this.getClass() == o.getClass()) {
|
||||||
|
AbstractUnaryNode that = (AbstractUnaryNode)o;
|
||||||
|
return this.operand.relaxedEquals(that.operand);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int relaxedHashCode() {
|
||||||
|
int result = 1;
|
||||||
|
result = 31 * result + this.getClass().hashCode();
|
||||||
|
result = 31 * result + this.operand.relaxedHashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract AstNode newInstance(AstNode var1);
|
||||||
|
|
||||||
|
public AstNode transform(AstTransformer transformer) {
|
||||||
|
AstNode operand = this.operand.transform(transformer);
|
||||||
|
return this.operand == operand ? transformer.transform(this) : transformer.transform(this.newInstance(operand));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String operandMethod = context.newSingleMethod(this.operand);
|
||||||
|
context.callDelegateSingle(m, operandMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
String operandMethod = context.newMultiMethod(this.operand);
|
||||||
|
context.callDelegateMulti(m, operandMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.unary;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class CubeNode extends AbstractUnaryNode {
|
||||||
|
public CubeNode(AstNode operand) {
|
||||||
|
super(operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AstNode newInstance(AstNode operand) {
|
||||||
|
return new CubeNode(operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
double v = this.operand.evalSingle(x, y, z, type);
|
||||||
|
return v * v * v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
this.operand.evalMulti(res, x, y, z, type);
|
||||||
|
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
res[i] = res[i] * res[i] * res[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
super.doBytecodeGenSingle(context, m, localVarConsumer);
|
||||||
|
m.dup2();
|
||||||
|
m.dup2();
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
super.doBytecodeGenMulti(context, m, localVarConsumer);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.dup2();
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.unary;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import org.objectweb.asm.Label;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class NegMulNode extends AbstractUnaryNode {
|
||||||
|
private final double negMul;
|
||||||
|
|
||||||
|
public NegMulNode(AstNode operand, double negMul) {
|
||||||
|
super(operand);
|
||||||
|
this.negMul = negMul;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AstNode newInstance(AstNode operand) {
|
||||||
|
return new NegMulNode(operand, this.negMul);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
double v = this.operand.evalSingle(x, y, z, type);
|
||||||
|
return v > 0.0 ? v : v * this.negMul;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
this.operand.evalMulti(res, x, y, z, type);
|
||||||
|
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
double v = res[i];
|
||||||
|
res[i] = v > 0.0 ? v : v * this.negMul;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
super.doBytecodeGenSingle(context, m, localVarConsumer);
|
||||||
|
int v = localVarConsumer.createLocalVariable("v", Type.DOUBLE_TYPE.getDescriptor());
|
||||||
|
m.store(v, Type.DOUBLE_TYPE);
|
||||||
|
Label negMulLabel = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
m.load(v, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.0);
|
||||||
|
m.cmpl(Type.DOUBLE_TYPE);
|
||||||
|
m.ifle(negMulLabel);
|
||||||
|
m.load(v, Type.DOUBLE_TYPE);
|
||||||
|
m.goTo(end);
|
||||||
|
m.visitLabel(negMulLabel);
|
||||||
|
m.load(v, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.negMul);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.visitLabel(end);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
super.doBytecodeGenMulti(context, m, localVarConsumer);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
int v = localVarConsumer.createLocalVariable("v", Type.DOUBLE_TYPE.getDescriptor());
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.store(v, Type.DOUBLE_TYPE);
|
||||||
|
Label negMulLabel = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
m.load(v, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(0.0);
|
||||||
|
m.cmpl(Type.DOUBLE_TYPE);
|
||||||
|
m.ifle(negMulLabel);
|
||||||
|
m.load(v, Type.DOUBLE_TYPE);
|
||||||
|
m.goTo(end);
|
||||||
|
m.visitLabel(negMulLabel);
|
||||||
|
m.load(v, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(this.negMul);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.visitLabel(end);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.unary;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class SquareNode extends AbstractUnaryNode {
|
||||||
|
public SquareNode(AstNode operand) {
|
||||||
|
super(operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AstNode newInstance(AstNode operand) {
|
||||||
|
return new SquareNode(operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
double v = this.operand.evalSingle(x, y, z, type);
|
||||||
|
return v * v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
this.operand.evalMulti(res, x, y, z, type);
|
||||||
|
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
res[i] *= res[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
super.doBytecodeGenSingle(context, m, localVarConsumer);
|
||||||
|
m.dup2();
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
super.doBytecodeGenMulti(context, m, localVarConsumer);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast.unary;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class SqueezeNode extends AbstractUnaryNode {
|
||||||
|
public SqueezeNode(AstNode operand) {
|
||||||
|
super(operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AstNode newInstance(AstNode operand) {
|
||||||
|
return new SqueezeNode(operand);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double evalSingle(int x, int y, int z, EvalType type) {
|
||||||
|
double v = Mth.clamp(this.operand.evalSingle(x, y, z, type), -1.0, 1.0);
|
||||||
|
return v / 2.0 - v * v * v / 24.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
this.operand.evalMulti(res, x, y, z, type);
|
||||||
|
|
||||||
|
for(int i = 0; i < res.length; ++i) {
|
||||||
|
double v = Mth.clamp(res[i], -1.0, 1.0);
|
||||||
|
res[i] = v / 2.0 - v * v * v / 24.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
super.doBytecodeGenSingle(context, m, localVarConsumer);
|
||||||
|
m.dconst(1.0);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "min", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
|
||||||
|
m.dconst(-1.0);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "max", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
|
||||||
|
int v = localVarConsumer.createLocalVariable("v", Type.DOUBLE_TYPE.getDescriptor());
|
||||||
|
m.store(v, Type.DOUBLE_TYPE);
|
||||||
|
m.load(v, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(2.0);
|
||||||
|
m.div(Type.DOUBLE_TYPE);
|
||||||
|
m.load(v, Type.DOUBLE_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.dup2();
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(24.0);
|
||||||
|
m.div(Type.DOUBLE_TYPE);
|
||||||
|
m.sub(Type.DOUBLE_TYPE);
|
||||||
|
m.areturn(Type.DOUBLE_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doBytecodeGenMulti(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
|
||||||
|
super.doBytecodeGenMulti(context, m, localVarConsumer);
|
||||||
|
context.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
int v = localVarConsumer.createLocalVariable("v", Type.DOUBLE_TYPE.getDescriptor());
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.aload(Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(1.0);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "min", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
|
||||||
|
m.dconst(-1.0);
|
||||||
|
m.invokestatic(Type.getInternalName(Math.class), "max", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
|
||||||
|
m.store(v, Type.DOUBLE_TYPE);
|
||||||
|
m.load(v, Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(2.0);
|
||||||
|
m.div(Type.DOUBLE_TYPE);
|
||||||
|
m.load(v, Type.DOUBLE_TYPE);
|
||||||
|
m.dup2();
|
||||||
|
m.dup2();
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.mul(Type.DOUBLE_TYPE);
|
||||||
|
m.dconst(24.0);
|
||||||
|
m.div(Type.DOUBLE_TYPE);
|
||||||
|
m.sub(Type.DOUBLE_TYPE);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ducks;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.util.ArrayCache;
|
||||||
|
|
||||||
|
public interface IArrayCacheCapable {
|
||||||
|
ArrayCache c2me$getArrayCache();
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ducks;
|
||||||
|
|
||||||
|
public interface IBlendingAwareVisitor {
|
||||||
|
boolean c2me$isBlendingEnabled();
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ducks;
|
||||||
|
|
||||||
|
public interface ICoordinatesFilling {
|
||||||
|
void c2me$fillCoordinates(int[] var1, int[] var2, int[] var3);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ducks;
|
||||||
|
|
||||||
|
public interface IEqualityOverriding {
|
||||||
|
void c2me$overrideEquality(Object var1);
|
||||||
|
|
||||||
|
Object c2me$getOverriddenEquality();
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ducks;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
|
||||||
|
public interface IFastCacheLike extends DensityFunction {
|
||||||
|
long CACHE_MISS_NAN_BITS = 9222769054270909007L;
|
||||||
|
|
||||||
|
double c2me$getCached(int var1, int var2, int var3, EvalType var4);
|
||||||
|
|
||||||
|
boolean c2me$getCached(double[] var1, int[] var2, int[] var3, int[] var4, EvalType var5);
|
||||||
|
|
||||||
|
void c2me$cache(int var1, int var2, int var3, EvalType var4, double var5);
|
||||||
|
|
||||||
|
void c2me$cache(double[] var1, int[] var2, int[] var3, int[] var4, EvalType var5);
|
||||||
|
|
||||||
|
DensityFunction c2me$getDelegate();
|
||||||
|
|
||||||
|
DensityFunction c2me$withDelegate(DensityFunction var1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,499 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.gen;
|
||||||
|
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.McToAst;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.dfvisitor.StripBlending;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.misc.ConstantNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.misc.RootNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.util.ArrayCache;
|
||||||
|
import org.bxteam.divinemc.dfc.common.vif.AstVanillaInterface;
|
||||||
|
import it.unimi.dsi.fastutil.Hash;
|
||||||
|
import it.unimi.dsi.fastutil.Pair;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntObjectPair;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ReferenceMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ReferenceMaps;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenCustomHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.IntConsumer;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import net.minecraft.util.CubicSpline;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunctions;
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.Label;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
import org.objectweb.asm.commons.AnalyzerAdapter;
|
||||||
|
import org.objectweb.asm.commons.InstructionAdapter;
|
||||||
|
|
||||||
|
public class BytecodeGen {
|
||||||
|
private static final File exportDir = new File("./cache/c2me-dfc");
|
||||||
|
private static final AtomicLong ordinal = new AtomicLong();
|
||||||
|
public static final Hash.Strategy<AstNode> RELAXED_STRATEGY;
|
||||||
|
private static final Object2ReferenceMap<AstNode, Class<?>> compilationCache;
|
||||||
|
|
||||||
|
public BytecodeGen() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DensityFunction compile(DensityFunction densityFunction, Reference2ReferenceMap<DensityFunction, DensityFunction> tempCache) {
|
||||||
|
DensityFunction cached = (DensityFunction)tempCache.get(densityFunction);
|
||||||
|
if (cached != null) {
|
||||||
|
return cached;
|
||||||
|
} else if (densityFunction instanceof AstVanillaInterface) {
|
||||||
|
AstVanillaInterface vif = (AstVanillaInterface)densityFunction;
|
||||||
|
AstNode ast = vif.getAstNode();
|
||||||
|
return new CompiledDensityFunction(compile0(ast), vif.getBlendingFallback());
|
||||||
|
} else {
|
||||||
|
AstNode ast = McToAst.toAst(densityFunction.mapAll(StripBlending.INSTANCE));
|
||||||
|
if (ast instanceof ConstantNode) {
|
||||||
|
ConstantNode constantNode = (ConstantNode)ast;
|
||||||
|
return DensityFunctions.constant(constantNode.getValue());
|
||||||
|
} else {
|
||||||
|
CompiledDensityFunction compiled = new CompiledDensityFunction(compile0(ast), densityFunction);
|
||||||
|
tempCache.put(densityFunction, compiled);
|
||||||
|
return compiled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized CompiledEntry compile0(AstNode node) {
|
||||||
|
Class<?> cached = (Class)compilationCache.get(node);
|
||||||
|
ClassWriter writer = new ClassWriter(3);
|
||||||
|
String name = cached != null ? String.format("DfcCompiled_discarded") : String.format("DfcCompiled_%d", ordinal.getAndIncrement());
|
||||||
|
writer.visit(65, 17, name, (String)null, Type.getInternalName(Object.class), new String[]{Type.getInternalName(CompiledEntry.class)});
|
||||||
|
RootNode rootNode = new RootNode(node);
|
||||||
|
Context genContext = new Context(writer, name);
|
||||||
|
genContext.newSingleMethod0((adapter, localVarConsumer) -> {
|
||||||
|
rootNode.doBytecodeGenSingle(genContext, adapter, localVarConsumer);
|
||||||
|
}, "evalSingle", true);
|
||||||
|
genContext.newMultiMethod0((adapter, localVarConsumer) -> {
|
||||||
|
rootNode.doBytecodeGenMulti(genContext, adapter, localVarConsumer);
|
||||||
|
}, "evalMulti", true);
|
||||||
|
List<Object> args = (List)genContext.args.entrySet().stream().sorted(Comparator.comparingInt((o) -> {
|
||||||
|
return ((Context.FieldRecord)o.getValue()).ordinal();
|
||||||
|
})).map(Map.Entry::getKey).collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
if (cached != null) {
|
||||||
|
try {
|
||||||
|
return (CompiledEntry)cached.getConstructor(List.class).newInstance(args);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | InstantiationException var11) {
|
||||||
|
ReflectiveOperationException e = var11;
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
genConstructor(genContext);
|
||||||
|
genGetArgs(genContext);
|
||||||
|
genNewInstance(genContext);
|
||||||
|
|
||||||
|
Object var8;
|
||||||
|
for(ListIterator<Object> iterator = args.listIterator(); iterator.hasNext(); var8 = iterator.next()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] bytes = writer.toByteArray();
|
||||||
|
dumpClass(genContext.className, bytes);
|
||||||
|
Class<?> defined = defineClass(genContext.className, bytes);
|
||||||
|
compilationCache.put(node, defined);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return (CompiledEntry)defined.getConstructor(List.class).newInstance(args);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | InstantiationException var12) {
|
||||||
|
ReflectiveOperationException e = var12;
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void genConstructor(Context context) {
|
||||||
|
InstructionAdapter m = new InstructionAdapter(new AnalyzerAdapter(context.className, 1, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.getType(List.class)}), context.classWriter.visitMethod(1, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.getType(List.class)}), (String)null, (String[])null)));
|
||||||
|
Label start = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
m.visitLabel(start);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokespecial(Type.getInternalName(Object.class), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[0]), false);
|
||||||
|
Iterator var4 = context.args.entrySet().stream().sorted(Comparator.comparingInt((o) -> {
|
||||||
|
return ((Context.FieldRecord)o.getValue()).ordinal();
|
||||||
|
})).toList().iterator();
|
||||||
|
|
||||||
|
while(var4.hasNext()) {
|
||||||
|
Map.Entry<Object, Context.FieldRecord> entry = (Map.Entry)var4.next();
|
||||||
|
String name = ((Context.FieldRecord)entry.getValue()).name();
|
||||||
|
Class<?> type = ((Context.FieldRecord)entry.getValue()).type();
|
||||||
|
int ordinal = ((Context.FieldRecord)entry.getValue()).ordinal();
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.iconst(ordinal);
|
||||||
|
m.invokeinterface(Type.getInternalName(List.class), "get", Type.getMethodDescriptor(InstructionAdapter.OBJECT_TYPE, new Type[]{Type.INT_TYPE}));
|
||||||
|
m.checkcast(Type.getType(type));
|
||||||
|
m.putfield(context.className, name, Type.getDescriptor(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
var4 = context.postProcessMethods.stream().sorted().toList().iterator();
|
||||||
|
|
||||||
|
while(var4.hasNext()) {
|
||||||
|
String postProcessingMethod = (String)var4.next();
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(context.className, postProcessingMethod, "()V", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.areturn(Type.VOID_TYPE);
|
||||||
|
m.visitLabel(end);
|
||||||
|
m.visitLocalVariable("this", context.classDesc, (String)null, start, end, 0);
|
||||||
|
m.visitLocalVariable("list", Type.getDescriptor(List.class), (String)null, start, end, 1);
|
||||||
|
m.visitMaxs(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void genGetArgs(Context context) {
|
||||||
|
InstructionAdapter m = new InstructionAdapter(new AnalyzerAdapter(context.className, 17, "getArgs", Type.getMethodDescriptor(Type.getType(List.class), new Type[0]), context.classWriter.visitMethod(17, "getArgs", Type.getMethodDescriptor(Type.getType(List.class), new Type[0]), (String)null, (String[])null)));
|
||||||
|
Label start = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
m.visitLabel(start);
|
||||||
|
m.anew(Type.getType(ArrayList.class));
|
||||||
|
m.dup();
|
||||||
|
m.iconst(context.args.size());
|
||||||
|
m.invokespecial(Type.getInternalName(ArrayList.class), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.INT_TYPE}), false);
|
||||||
|
m.store(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
Iterator var4 = context.args.entrySet().stream().sorted(Comparator.comparingInt((o) -> {
|
||||||
|
return ((Context.FieldRecord)o.getValue()).ordinal();
|
||||||
|
})).toList().iterator();
|
||||||
|
|
||||||
|
while(var4.hasNext()) {
|
||||||
|
Map.Entry<Object, Context.FieldRecord> entry = (Map.Entry)var4.next();
|
||||||
|
String name = ((Context.FieldRecord)entry.getValue()).name();
|
||||||
|
Class<?> type = ((Context.FieldRecord)entry.getValue()).type();
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.getfield(context.className, name, Type.getDescriptor(type));
|
||||||
|
m.invokeinterface(Type.getInternalName(List.class), "add", Type.getMethodDescriptor(Type.BOOLEAN_TYPE, new Type[]{InstructionAdapter.OBJECT_TYPE}));
|
||||||
|
m.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.areturn(InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.visitLabel(end);
|
||||||
|
m.visitLocalVariable("this", context.classDesc, (String)null, start, end, 0);
|
||||||
|
m.visitLocalVariable("list", Type.getDescriptor(List.class), (String)null, start, end, 1);
|
||||||
|
m.visitMaxs(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void genNewInstance(Context context) {
|
||||||
|
InstructionAdapter m = new InstructionAdapter(new AnalyzerAdapter(context.className, 17, "newInstance", Type.getMethodDescriptor(Type.getType(CompiledEntry.class), new Type[]{Type.getType(List.class)}), context.classWriter.visitMethod(17, "newInstance", Type.getMethodDescriptor(Type.getType(CompiledEntry.class), new Type[]{Type.getType(List.class)}), (String)null, (String[])null)));
|
||||||
|
Label start = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
m.visitLabel(start);
|
||||||
|
m.anew(Type.getType(context.classDesc));
|
||||||
|
m.dup();
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokespecial(context.className, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.getType(List.class)}), false);
|
||||||
|
m.areturn(InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.visitLabel(end);
|
||||||
|
m.visitLocalVariable("this", context.classDesc, (String)null, start, end, 0);
|
||||||
|
m.visitLocalVariable("list", Type.getDescriptor(List.class), (String)null, start, end, 1);
|
||||||
|
m.visitMaxs(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void dumpClass(String className, byte[] bytes) {
|
||||||
|
File outputFile = new File(exportDir, className + ".class");
|
||||||
|
outputFile.getParentFile().mkdirs();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.write(bytes, outputFile);
|
||||||
|
} catch (IOException var4) {
|
||||||
|
IOException e = var4;
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Class<?> defineClass(final String className, final byte[] bytes) {
|
||||||
|
ClassLoader classLoader = new ClassLoader(BytecodeGen.class.getClassLoader()) {
|
||||||
|
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||||
|
return name.equals(className) ? super.defineClass(name, bytes, 0, bytes.length) : super.loadClass(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
return classLoader.loadClass(className);
|
||||||
|
} catch (ClassNotFoundException var4) {
|
||||||
|
ClassNotFoundException e = var4;
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
org.bxteam.divinemc.util.Files.deleteRecursively(exportDir);
|
||||||
|
} catch (IOException var1) {
|
||||||
|
IOException e = var1;
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
RELAXED_STRATEGY = new Hash.Strategy<AstNode>() {
|
||||||
|
public int hashCode(AstNode o) {
|
||||||
|
return o.relaxedHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(AstNode a, AstNode b) {
|
||||||
|
return a.relaxedEquals(b);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
compilationCache = Object2ReferenceMaps.synchronize(new Object2ReferenceOpenCustomHashMap<>(RELAXED_STRATEGY));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Context {
|
||||||
|
public static final String SINGLE_DESC;
|
||||||
|
public static final String MULTI_DESC;
|
||||||
|
public final ClassWriter classWriter;
|
||||||
|
public final String className;
|
||||||
|
public final String classDesc;
|
||||||
|
private int methodIdx = 0;
|
||||||
|
private final Object2ReferenceOpenHashMap<AstNode, String> singleMethods = new Object2ReferenceOpenHashMap<>();
|
||||||
|
private final Object2ReferenceOpenHashMap<AstNode, String> multiMethods = new Object2ReferenceOpenHashMap<>();
|
||||||
|
private final Object2ReferenceOpenHashMap<CubicSpline<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate>, String> splineMethods = new Object2ReferenceOpenHashMap<>();
|
||||||
|
private final ObjectOpenHashSet<String> postProcessMethods = new ObjectOpenHashSet<>();
|
||||||
|
private final Reference2ObjectOpenHashMap<Object, FieldRecord> args = new Reference2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
public Context(ClassWriter classWriter, String className) {
|
||||||
|
this.classWriter = (ClassWriter)Objects.requireNonNull(classWriter);
|
||||||
|
this.className = (String)Objects.requireNonNull(className);
|
||||||
|
this.classDesc = String.format("L%s;", this.className);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String nextMethodName() {
|
||||||
|
return String.format("method_%d", this.methodIdx++);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String nextMethodName(String suffix) {
|
||||||
|
return String.format("method_%d_%s", this.methodIdx++, suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String newSingleMethod(AstNode node) {
|
||||||
|
return this.singleMethods.computeIfAbsent(node, (AstNode node1) -> this.newSingleMethod((adapter, localVarConsumer) -> node1.doBytecodeGenSingle(this, adapter, localVarConsumer), nextMethodName(node.getClass().getSimpleName())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String newSingleMethod(BiConsumer<InstructionAdapter, LocalVarConsumer> generator) {
|
||||||
|
return this.newSingleMethod(generator, this.nextMethodName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String newSingleMethod(BiConsumer<InstructionAdapter, LocalVarConsumer> generator, String name) {
|
||||||
|
this.newSingleMethod0(generator, name, false);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newSingleMethod0(BiConsumer<InstructionAdapter, LocalVarConsumer> generator, String name, boolean isPublic) {
|
||||||
|
InstructionAdapter adapter = new InstructionAdapter(new AnalyzerAdapter(this.className, (isPublic ? 1 : 2) | 16, name, SINGLE_DESC, this.classWriter.visitMethod((isPublic ? 1 : 2) | 16, name, SINGLE_DESC, (String)null, (String[])null)));
|
||||||
|
List<IntObjectPair<Pair<String, String>>> extraLocals = new ArrayList<>();
|
||||||
|
Label start = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
adapter.visitLabel(start);
|
||||||
|
generator.accept(adapter, (localName, localDesc) -> {
|
||||||
|
int ordinal = extraLocals.size() + 5;
|
||||||
|
extraLocals.add(IntObjectPair.of(ordinal, Pair.of(localName, localDesc)));
|
||||||
|
return ordinal;
|
||||||
|
});
|
||||||
|
adapter.visitLabel(end);
|
||||||
|
adapter.visitLocalVariable("this", this.classDesc, (String)null, start, end, 0);
|
||||||
|
adapter.visitLocalVariable("x", Type.INT_TYPE.getDescriptor(), (String)null, start, end, 1);
|
||||||
|
adapter.visitLocalVariable("y", Type.INT_TYPE.getDescriptor(), (String)null, start, end, 2);
|
||||||
|
adapter.visitLocalVariable("z", Type.INT_TYPE.getDescriptor(), (String)null, start, end, 3);
|
||||||
|
adapter.visitLocalVariable("evalType", Type.getType(EvalType.class).getDescriptor(), (String)null, start, end, 4);
|
||||||
|
Iterator var8 = extraLocals.iterator();
|
||||||
|
|
||||||
|
while(var8.hasNext()) {
|
||||||
|
IntObjectPair<Pair<String, String>> local = (IntObjectPair)var8.next();
|
||||||
|
adapter.visitLocalVariable((String)((Pair)local.right()).left(), (String)((Pair)local.right()).right(), (String)null, start, end, local.leftInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.visitMaxs(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String newMultiMethod(AstNode node) {
|
||||||
|
return this.multiMethods.computeIfAbsent(node, (AstNode node1) -> this.newMultiMethod((adapter, localVarConsumer) -> node1.doBytecodeGenMulti(this, adapter, localVarConsumer), nextMethodName(node.getClass().getSimpleName())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String newMultiMethod(BiConsumer<InstructionAdapter, LocalVarConsumer> generator) {
|
||||||
|
return this.newMultiMethod(generator, this.nextMethodName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String newMultiMethod(BiConsumer<InstructionAdapter, LocalVarConsumer> generator, String name) {
|
||||||
|
this.newMultiMethod0(generator, name, false);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void newMultiMethod0(BiConsumer<InstructionAdapter, LocalVarConsumer> generator, String name, boolean isPublic) {
|
||||||
|
InstructionAdapter adapter = new InstructionAdapter(new AnalyzerAdapter(this.className, (isPublic ? 1 : 2) | 16, name, MULTI_DESC, this.classWriter.visitMethod((isPublic ? 1 : 2) | 16, name, MULTI_DESC, (String)null, (String[])null)));
|
||||||
|
List<IntObjectPair<Pair<String, String>>> extraLocals = new ArrayList();
|
||||||
|
Label start = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
adapter.visitLabel(start);
|
||||||
|
generator.accept(adapter, (localName, localDesc) -> {
|
||||||
|
int ordinal = extraLocals.size() + 7;
|
||||||
|
extraLocals.add(IntObjectPair.of(ordinal, Pair.of(localName, localDesc)));
|
||||||
|
return ordinal;
|
||||||
|
});
|
||||||
|
adapter.visitLabel(end);
|
||||||
|
adapter.visitLocalVariable("this", this.classDesc, (String)null, start, end, 0);
|
||||||
|
adapter.visitLocalVariable("res", Type.getType(double[].class).getDescriptor(), (String)null, start, end, 1);
|
||||||
|
adapter.visitLocalVariable("x", Type.getType(double[].class).getDescriptor(), (String)null, start, end, 2);
|
||||||
|
adapter.visitLocalVariable("y", Type.getType(double[].class).getDescriptor(), (String)null, start, end, 3);
|
||||||
|
adapter.visitLocalVariable("z", Type.getType(double[].class).getDescriptor(), (String)null, start, end, 4);
|
||||||
|
adapter.visitLocalVariable("evalType", Type.getType(EvalType.class).getDescriptor(), (String)null, start, end, 5);
|
||||||
|
adapter.visitLocalVariable("arrayCache", Type.getType(ArrayCache.class).getDescriptor(), (String)null, start, end, 6);
|
||||||
|
Iterator var8 = extraLocals.iterator();
|
||||||
|
|
||||||
|
while(var8.hasNext()) {
|
||||||
|
IntObjectPair<Pair<String, String>> local = (IntObjectPair)var8.next();
|
||||||
|
adapter.visitLocalVariable((String)((Pair)local.right()).left(), (String)((Pair)local.right()).right(), (String)null, start, end, local.leftInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.visitMaxs(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCachedSplineMethod(CubicSpline<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> spline) {
|
||||||
|
return (String)this.splineMethods.get(spline);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cacheSplineMethod(CubicSpline<DensityFunctions.Spline.Point, DensityFunctions.Spline.Coordinate> spline, String method) {
|
||||||
|
this.splineMethods.put(spline, method);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callDelegateSingle(InstructionAdapter m, String target) {
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(1, Type.INT_TYPE);
|
||||||
|
m.load(2, Type.INT_TYPE);
|
||||||
|
m.load(3, Type.INT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(this.className, target, SINGLE_DESC, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void callDelegateMulti(InstructionAdapter m, String target) {
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(6, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(this.className, target, MULTI_DESC, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> String newField(Class<T> type, T data) {
|
||||||
|
FieldRecord existing = (FieldRecord)this.args.get(data);
|
||||||
|
if (existing != null) {
|
||||||
|
return existing.name();
|
||||||
|
} else {
|
||||||
|
int size = this.args.size();
|
||||||
|
String name = String.format("field_%d", size);
|
||||||
|
this.classWriter.visitField(2, name, Type.getDescriptor(type), (String)null, (Object)null);
|
||||||
|
this.args.put(data, new FieldRecord(name, size, type));
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doCountedLoop(InstructionAdapter m, LocalVarConsumer localVarConsumer, IntConsumer bodyGenerator) {
|
||||||
|
int loopIdx = localVarConsumer.createLocalVariable("loopIdx", Type.INT_TYPE.getDescriptor());
|
||||||
|
m.iconst(0);
|
||||||
|
m.store(loopIdx, Type.INT_TYPE);
|
||||||
|
Label start = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
m.visitLabel(start);
|
||||||
|
m.load(loopIdx, Type.INT_TYPE);
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.arraylength();
|
||||||
|
m.ificmpge(end);
|
||||||
|
bodyGenerator.accept(loopIdx);
|
||||||
|
m.iinc(loopIdx, 1);
|
||||||
|
m.goTo(start);
|
||||||
|
m.visitLabel(end);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void delegateToSingle(InstructionAdapter m, LocalVarConsumer localVarConsumer, AstNode current) {
|
||||||
|
String singleMethod = this.newSingleMethod(current);
|
||||||
|
this.doCountedLoop(m, localVarConsumer, (idx) -> {
|
||||||
|
m.load(1, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.load(0, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(2, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(3, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(4, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.load(idx, Type.INT_TYPE);
|
||||||
|
m.aload(Type.INT_TYPE);
|
||||||
|
m.load(5, InstructionAdapter.OBJECT_TYPE);
|
||||||
|
m.invokevirtual(this.className, singleMethod, SINGLE_DESC, false);
|
||||||
|
m.astore(Type.DOUBLE_TYPE);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void genPostprocessingMethod(String name, Consumer<InstructionAdapter> generator) {
|
||||||
|
if (!this.postProcessMethods.contains(name)) {
|
||||||
|
InstructionAdapter adapter = new InstructionAdapter(new AnalyzerAdapter(this.className, 18, name, "()V", this.classWriter.visitMethod(18, name, "()V", (String)null, (String[])null)));
|
||||||
|
Label start = new Label();
|
||||||
|
Label end = new Label();
|
||||||
|
adapter.visitLabel(start);
|
||||||
|
generator.accept(adapter);
|
||||||
|
adapter.visitLabel(end);
|
||||||
|
adapter.visitMaxs(0, 0);
|
||||||
|
adapter.visitLocalVariable("this", this.classDesc, (String)null, start, end, 0);
|
||||||
|
this.postProcessMethods.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
SINGLE_DESC = Type.getMethodDescriptor(Type.getType(Double.TYPE), new Type[]{Type.getType(Integer.TYPE), Type.getType(Integer.TYPE), Type.getType(Integer.TYPE), Type.getType(EvalType.class)});
|
||||||
|
MULTI_DESC = Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.getType(double[].class), Type.getType(int[].class), Type.getType(int[].class), Type.getType(int[].class), Type.getType(EvalType.class), Type.getType(ArrayCache.class)});
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface LocalVarConsumer {
|
||||||
|
int createLocalVariable(String var1, String var2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static record FieldRecord(String name, int ordinal, Class<?> type) {
|
||||||
|
private FieldRecord(String name, int ordinal, Class<?> type) {
|
||||||
|
this.name = name;
|
||||||
|
this.ordinal = ordinal;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ordinal() {
|
||||||
|
return this.ordinal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> type() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface EvalMultiInterface {
|
||||||
|
void evalMulti(double[] var1, int[] var2, int[] var3, int[] var4, EvalType var5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface EvalSingleInterface {
|
||||||
|
double evalSingle(int var1, int var2, int var3, EvalType var4);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.gen;
|
||||||
|
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ducks.IBlendingAwareVisitor;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ducks.IFastCacheLike;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
|
||||||
|
public class CompiledDensityFunction extends SubCompiledDensityFunction {
|
||||||
|
private final CompiledEntry compiledEntry;
|
||||||
|
|
||||||
|
public CompiledDensityFunction(CompiledEntry compiledEntry, DensityFunction blendingFallback) {
|
||||||
|
super(compiledEntry, compiledEntry, blendingFallback);
|
||||||
|
this.compiledEntry = (CompiledEntry)Objects.requireNonNull(compiledEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CompiledDensityFunction(CompiledEntry compiledEntry, Supplier<DensityFunction> blendingFallback) {
|
||||||
|
super(compiledEntry, compiledEntry, blendingFallback);
|
||||||
|
this.compiledEntry = (CompiledEntry)Objects.requireNonNull(compiledEntry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DensityFunction mapAll(Visitor visitor) {
|
||||||
|
if (visitor instanceof IBlendingAwareVisitor blendingAwareVisitor) {
|
||||||
|
if (blendingAwareVisitor.c2me$isBlendingEnabled()) {
|
||||||
|
DensityFunction fallback1 = this.getFallback();
|
||||||
|
if (fallback1 == null) {
|
||||||
|
throw new IllegalStateException("blendingFallback is no more");
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallback1.mapAll(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean modified = false;
|
||||||
|
List<Object> args = this.compiledEntry.getArgs();
|
||||||
|
ListIterator<Object> iterator = args.listIterator();
|
||||||
|
|
||||||
|
Object next;
|
||||||
|
while(iterator.hasNext()) {
|
||||||
|
next = iterator.next();
|
||||||
|
if (next instanceof DensityFunction df) {
|
||||||
|
if (!(df instanceof IFastCacheLike)) {
|
||||||
|
DensityFunction applied = df.mapAll(visitor);
|
||||||
|
if (df != applied) {
|
||||||
|
iterator.set(applied);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next instanceof NoiseHolder noise) {
|
||||||
|
NoiseHolder applied = visitor.visitNoise(noise);
|
||||||
|
if (noise != applied) {
|
||||||
|
iterator.set(applied);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator = args.listIterator();
|
||||||
|
|
||||||
|
while(iterator.hasNext()) {
|
||||||
|
next = iterator.next();
|
||||||
|
if (next instanceof IFastCacheLike cacheLike) {
|
||||||
|
DensityFunction applied = visitor.apply(cacheLike);
|
||||||
|
if (applied == cacheLike.c2me$getDelegate()) {
|
||||||
|
iterator.set((Object)null);
|
||||||
|
modified = true;
|
||||||
|
} else {
|
||||||
|
if (!(applied instanceof IFastCacheLike)) {
|
||||||
|
throw new UnsupportedOperationException("Unsupported transformation on Wrapping node");
|
||||||
|
}
|
||||||
|
|
||||||
|
IFastCacheLike newCacheLike = (IFastCacheLike)applied;
|
||||||
|
iterator.set(newCacheLike);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Supplier<DensityFunction> fallback = this.blendingFallback != null ? Suppliers.memoize(() -> {
|
||||||
|
DensityFunction densityFunction = (DensityFunction)this.blendingFallback.get();
|
||||||
|
return densityFunction != null ? densityFunction.mapAll(visitor) : null;
|
||||||
|
}) : null;
|
||||||
|
if (fallback != this.blendingFallback) {
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modified) {
|
||||||
|
return new CompiledDensityFunction(this.compiledEntry.newInstance(args), fallback);
|
||||||
|
} else {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.gen;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.util.ArrayCache;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface CompiledEntry extends ISingleMethod, IMultiMethod {
|
||||||
|
double evalSingle(int var1, int var2, int var3, EvalType var4);
|
||||||
|
|
||||||
|
void evalMulti(double[] var1, int[] var2, int[] var3, int[] var4, EvalType var5, ArrayCache var6);
|
||||||
|
|
||||||
|
CompiledEntry newInstance(List<?> var1);
|
||||||
|
|
||||||
|
List<Object> getArgs();
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.gen;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ducks.IBlendingAwareVisitor;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class DelegatingBlendingAwareVisitor implements IBlendingAwareVisitor, DensityFunction.Visitor {
|
||||||
|
private final DensityFunction.Visitor delegate;
|
||||||
|
private final boolean blendingEnabled;
|
||||||
|
|
||||||
|
public DelegatingBlendingAwareVisitor(DensityFunction.Visitor delegate, boolean blendingEnabled) {
|
||||||
|
this.delegate = Objects.requireNonNull(delegate);
|
||||||
|
this.blendingEnabled = blendingEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NotNull DensityFunction apply(@NotNull DensityFunction densityFunction) {
|
||||||
|
return this.delegate.apply(densityFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DensityFunction.@NotNull NoiseHolder visitNoise(DensityFunction.@NotNull NoiseHolder noiseDensityFunction) {
|
||||||
|
return this.delegate.visitNoise(noiseDensityFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean c2me$isBlendingEnabled() {
|
||||||
|
return this.blendingEnabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.gen;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.util.ArrayCache;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface IMultiMethod {
|
||||||
|
void evalMulti(double[] var1, int[] var2, int[] var3, int[] var4, EvalType var5, ArrayCache var6);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.gen;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface ISingleMethod {
|
||||||
|
double evalSingle(int var1, int var2, int var3, EvalType var4);
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.gen;
|
||||||
|
|
||||||
|
import com.google.common.base.Suppliers;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ducks.IArrayCacheCapable;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ducks.IBlendingAwareVisitor;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ducks.ICoordinatesFilling;
|
||||||
|
import org.bxteam.divinemc.dfc.common.util.ArrayCache;
|
||||||
|
import org.bxteam.divinemc.dfc.common.vif.EachApplierVanillaInterface;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import net.minecraft.util.KeyDispatchDataCodec;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import net.minecraft.world.level.levelgen.NoiseChunk;
|
||||||
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class SubCompiledDensityFunction implements DensityFunction {
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(SubCompiledDensityFunction.class);
|
||||||
|
private final ISingleMethod singleMethod;
|
||||||
|
private final IMultiMethod multiMethod;
|
||||||
|
protected final Supplier<DensityFunction> blendingFallback;
|
||||||
|
|
||||||
|
public SubCompiledDensityFunction(ISingleMethod singleMethod, IMultiMethod multiMethod, DensityFunction blendingFallback) {
|
||||||
|
this(singleMethod, multiMethod, unwrap(blendingFallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SubCompiledDensityFunction(ISingleMethod singleMethod, IMultiMethod multiMethod, Supplier<DensityFunction> blendingFallback) {
|
||||||
|
this.singleMethod = (ISingleMethod)Objects.requireNonNull(singleMethod);
|
||||||
|
this.multiMethod = (IMultiMethod)Objects.requireNonNull(multiMethod);
|
||||||
|
this.blendingFallback = blendingFallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Supplier<DensityFunction> unwrap(DensityFunction densityFunction) {
|
||||||
|
if (densityFunction instanceof SubCompiledDensityFunction scdf) {
|
||||||
|
return scdf.blendingFallback;
|
||||||
|
} else {
|
||||||
|
return densityFunction != null ? Suppliers.ofInstance(densityFunction) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double compute(FunctionContext pos) {
|
||||||
|
if (pos.getBlender() != Blender.empty()) {
|
||||||
|
DensityFunction fallback = this.getFallback();
|
||||||
|
if (fallback == null) {
|
||||||
|
throw new IllegalStateException("blendingFallback is no more");
|
||||||
|
} else {
|
||||||
|
return fallback.compute(pos);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.singleMethod.evalSingle(pos.blockX(), pos.blockY(), pos.blockZ(), EvalType.from(pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillArray(double[] densities, ContextProvider applier) {
|
||||||
|
if (applier instanceof NoiseChunk sampler) {
|
||||||
|
if (sampler.getBlender() != Blender.empty()) {
|
||||||
|
DensityFunction fallback = this.getFallback();
|
||||||
|
if (fallback == null) {
|
||||||
|
throw new IllegalStateException("blendingFallback is no more");
|
||||||
|
}
|
||||||
|
|
||||||
|
fallback.fillArray(densities, applier);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (applier instanceof EachApplierVanillaInterface vanillaInterface) {
|
||||||
|
this.multiMethod.evalMulti(densities, vanillaInterface.getX(), vanillaInterface.getY(), vanillaInterface.getZ(), EvalType.from(applier), vanillaInterface.c2me$getArrayCache());
|
||||||
|
} else {
|
||||||
|
ArrayCache var10000;
|
||||||
|
if (applier instanceof IArrayCacheCapable cacheCapable) {
|
||||||
|
var10000 = cacheCapable.c2me$getArrayCache();
|
||||||
|
} else {
|
||||||
|
var10000 = new ArrayCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayCache cache = var10000;
|
||||||
|
int[] x = cache.getIntArray(densities.length, false);
|
||||||
|
int[] y = cache.getIntArray(densities.length, false);
|
||||||
|
int[] z = cache.getIntArray(densities.length, false);
|
||||||
|
if (applier instanceof ICoordinatesFilling coordinatesFilling) {
|
||||||
|
coordinatesFilling.c2me$fillCoordinates(x, y, z);
|
||||||
|
} else {
|
||||||
|
for(int i = 0; i < densities.length; ++i) {
|
||||||
|
FunctionContext pos = applier.forIndex(i);
|
||||||
|
x[i] = pos.blockX();
|
||||||
|
y[i] = pos.blockY();
|
||||||
|
z[i] = pos.blockZ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.multiMethod.evalMulti(densities, x, y, z, EvalType.from(applier), cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DensityFunction mapAll(Visitor visitor) {
|
||||||
|
if (this.getClass() != SubCompiledDensityFunction.class) {
|
||||||
|
throw new AbstractMethodError();
|
||||||
|
} else {
|
||||||
|
if (visitor instanceof IBlendingAwareVisitor) {
|
||||||
|
IBlendingAwareVisitor blendingAwareVisitor = (IBlendingAwareVisitor)visitor;
|
||||||
|
if (blendingAwareVisitor.c2me$isBlendingEnabled()) {
|
||||||
|
DensityFunction fallback1 = this.getFallback();
|
||||||
|
if (fallback1 == null) {
|
||||||
|
throw new IllegalStateException("blendingFallback is no more");
|
||||||
|
}
|
||||||
|
|
||||||
|
return fallback1.mapAll(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean modified = false;
|
||||||
|
Supplier<DensityFunction> fallback = this.blendingFallback != null ? Suppliers.memoize(() -> {
|
||||||
|
DensityFunction densityFunction = (DensityFunction)this.blendingFallback.get();
|
||||||
|
return densityFunction != null ? densityFunction.mapAll(visitor) : null;
|
||||||
|
}) : null;
|
||||||
|
if (fallback != this.blendingFallback) {
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return modified ? new SubCompiledDensityFunction(this.singleMethod, this.multiMethod, fallback) : this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double minValue() {
|
||||||
|
return Double.MIN_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double maxValue() {
|
||||||
|
return Double.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DensityFunction getFallback() {
|
||||||
|
return this.blendingFallback != null ? (DensityFunction)this.blendingFallback.get() : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.util;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ReferenceArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class ArrayCache {
|
||||||
|
private final Int2ReferenceArrayMap<ReferenceArrayList<double[]>> doubleArrayCache = new Int2ReferenceArrayMap<>();
|
||||||
|
private final Int2ReferenceArrayMap<ReferenceArrayList<int[]>> intArrayCache = new Int2ReferenceArrayMap<>();
|
||||||
|
|
||||||
|
public ArrayCache() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public double[] getDoubleArray(int size, boolean zero) {
|
||||||
|
ReferenceArrayList<double[]> list = this.doubleArrayCache.computeIfAbsent(size, (k) -> {
|
||||||
|
return new ReferenceArrayList<>();
|
||||||
|
});
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
return new double[size];
|
||||||
|
} else {
|
||||||
|
double[] popped = list.pop();
|
||||||
|
if (zero) {
|
||||||
|
Arrays.fill(popped, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return popped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getIntArray(int size, boolean zero) {
|
||||||
|
ReferenceArrayList<int[]> list = this.intArrayCache.computeIfAbsent(size, (k) -> {
|
||||||
|
return new ReferenceArrayList<>();
|
||||||
|
});
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
return new int[size];
|
||||||
|
} else {
|
||||||
|
int[] popped = list.pop();
|
||||||
|
if (zero) {
|
||||||
|
Arrays.fill(popped, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return popped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recycle(double[] array) {
|
||||||
|
this.doubleArrayCache.computeIfAbsent(array.length, (k) -> {
|
||||||
|
return new ReferenceArrayList<>();
|
||||||
|
}).add(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recycle(int[] array) {
|
||||||
|
this.intArrayCache.computeIfAbsent(array.length, (k) -> {
|
||||||
|
return new ReferenceArrayList<>();
|
||||||
|
}).add(array);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.vif;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.AstNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.misc.CacheLikeNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.misc.DelegateNode;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ducks.IFastCacheLike;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.util.KeyDispatchDataCodec;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
import net.minecraft.world.level.levelgen.NoiseChunk;
|
||||||
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||||
|
|
||||||
|
public class AstVanillaInterface implements DensityFunction {
|
||||||
|
private final AstNode astNode;
|
||||||
|
private final DensityFunction blendingFallback;
|
||||||
|
|
||||||
|
public AstVanillaInterface(AstNode astNode, DensityFunction blendingFallback) {
|
||||||
|
this.astNode = (AstNode)Objects.requireNonNull(astNode);
|
||||||
|
this.blendingFallback = blendingFallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double compute(FunctionContext pos) {
|
||||||
|
if (pos.getBlender() != Blender.empty()) {
|
||||||
|
if (this.blendingFallback == null) {
|
||||||
|
throw new IllegalStateException("blendingFallback is no more");
|
||||||
|
} else {
|
||||||
|
return this.blendingFallback.compute(pos);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return this.astNode.evalSingle(pos.blockX(), pos.blockY(), pos.blockZ(), EvalType.from(pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillArray(double[] densities, ContextProvider applier) {
|
||||||
|
if (applier instanceof NoiseChunk sampler) {
|
||||||
|
if (sampler.getBlender() != Blender.empty()) {
|
||||||
|
if (this.blendingFallback == null) {
|
||||||
|
throw new IllegalStateException("blendingFallback is no more");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.blendingFallback.fillArray(densities, applier);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (applier instanceof EachApplierVanillaInterface vanillaInterface) {
|
||||||
|
this.astNode.evalMulti(densities, vanillaInterface.getX(), vanillaInterface.getY(), vanillaInterface.getZ(), EvalType.from(applier));
|
||||||
|
} else {
|
||||||
|
int[] x = new int[densities.length];
|
||||||
|
int[] y = new int[densities.length];
|
||||||
|
int[] z = new int[densities.length];
|
||||||
|
|
||||||
|
for(int i = 0; i < densities.length; ++i) {
|
||||||
|
FunctionContext pos = applier.forIndex(i);
|
||||||
|
x[i] = pos.blockX();
|
||||||
|
y[i] = pos.blockY();
|
||||||
|
z[i] = pos.blockZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.astNode.evalMulti(densities, x, y, z, EvalType.from(applier));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DensityFunction mapAll(Visitor visitor) {
|
||||||
|
AstNode transformed = this.astNode.transform((astNode) -> {
|
||||||
|
if (astNode instanceof DelegateNode delegateNode) {
|
||||||
|
return new DelegateNode(delegateNode.getDelegate().mapAll(visitor));
|
||||||
|
} else if (astNode instanceof CacheLikeNode cacheLikeNode) {
|
||||||
|
return new CacheLikeNode((IFastCacheLike)cacheLikeNode.getCacheLike().mapAll(visitor), cacheLikeNode.getDelegate());
|
||||||
|
} else {
|
||||||
|
return astNode;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
DensityFunction blendingFallback1 = this.blendingFallback != null ? this.blendingFallback.mapAll(visitor) : null;
|
||||||
|
return transformed == this.astNode && blendingFallback1 == this.blendingFallback ? this : new AstVanillaInterface(transformed, blendingFallback1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double minValue() {
|
||||||
|
return this.blendingFallback.minValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double maxValue() {
|
||||||
|
return this.blendingFallback.maxValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AstNode getAstNode() {
|
||||||
|
return this.astNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DensityFunction getBlendingFallback() {
|
||||||
|
return this.blendingFallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.vif;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import org.bxteam.divinemc.dfc.common.ducks.IArrayCacheCapable;
|
||||||
|
import org.bxteam.divinemc.dfc.common.util.ArrayCache;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
|
||||||
|
public class EachApplierVanillaInterface implements DensityFunction.ContextProvider, IArrayCacheCapable {
|
||||||
|
private final int[] x;
|
||||||
|
private final int[] y;
|
||||||
|
private final int[] z;
|
||||||
|
private final EvalType type;
|
||||||
|
private final ArrayCache cache;
|
||||||
|
|
||||||
|
public EachApplierVanillaInterface(int[] x, int[] y, int[] z, EvalType type) {
|
||||||
|
this(x, y, z, type, new ArrayCache());
|
||||||
|
}
|
||||||
|
|
||||||
|
public EachApplierVanillaInterface(int[] x, int[] y, int[] z, EvalType type, ArrayCache cache) {
|
||||||
|
this.x = (int[])Objects.requireNonNull(x);
|
||||||
|
this.y = (int[])Objects.requireNonNull(y);
|
||||||
|
this.z = (int[])Objects.requireNonNull(z);
|
||||||
|
this.type = (EvalType)Objects.requireNonNull(type);
|
||||||
|
this.cache = (ArrayCache)Objects.requireNonNull(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DensityFunction.FunctionContext forIndex(int index) {
|
||||||
|
return new NoisePosVanillaInterface(this.x[index], this.y[index], this.z[index], this.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillAllDirectly(double[] densities, DensityFunction densityFunction) {
|
||||||
|
for(int i = 0; i < this.x.length; ++i) {
|
||||||
|
densities[i] = densityFunction.compute(this.forIndex(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getX() {
|
||||||
|
return this.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getY() {
|
||||||
|
return this.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getZ() {
|
||||||
|
return this.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EvalType getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayCache c2me$getArrayCache() {
|
||||||
|
return this.cache;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.vif;
|
||||||
|
|
||||||
|
import org.bxteam.divinemc.dfc.common.ast.EvalType;
|
||||||
|
import java.util.Objects;
|
||||||
|
import net.minecraft.world.level.levelgen.DensityFunction;
|
||||||
|
|
||||||
|
public class NoisePosVanillaInterface implements DensityFunction.FunctionContext {
|
||||||
|
private final int x;
|
||||||
|
private final int y;
|
||||||
|
private final int z;
|
||||||
|
private final EvalType type;
|
||||||
|
|
||||||
|
public NoisePosVanillaInterface(int x, int y, int z, EvalType type) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
this.type = (EvalType)Objects.requireNonNull(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int blockX() {
|
||||||
|
return this.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int blockY() {
|
||||||
|
return this.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int blockZ() {
|
||||||
|
return this.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EvalType getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package org.bxteam.divinemc.util;
|
||||||
|
|
||||||
|
public final class Assertions {
|
||||||
|
public static void assertTrue(boolean value, String message) {
|
||||||
|
if (!value) {
|
||||||
|
final AssertionError error = new AssertionError(message);
|
||||||
|
error.printStackTrace();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertTrue(boolean state, String format, Object... args) {
|
||||||
|
if (!state) {
|
||||||
|
final AssertionError error = new AssertionError(String.format(format, args));
|
||||||
|
error.printStackTrace();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertTrue(boolean value) {
|
||||||
|
if (!value) {
|
||||||
|
final AssertionError error = new AssertionError();
|
||||||
|
error.printStackTrace();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package org.bxteam.divinemc.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public final class Files {
|
||||||
|
public static void deleteRecursively(File dir) throws IOException {
|
||||||
|
if (dir == null || !dir.isDirectory()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
if (files == null) {
|
||||||
|
throw new IOException("Error enumerating directory during recursive delete operation: " + dir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (File child : files) {
|
||||||
|
if (child.isDirectory()) {
|
||||||
|
Files.deleteRecursively(child);
|
||||||
|
} else if (child.isFile()) {
|
||||||
|
if (!child.delete()) {
|
||||||
|
throw new IOException("Error deleting file during recursive delete operation: " + child.getAbsolutePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dir.delete()) {
|
||||||
|
throw new IOException("Error deleting directory during recursive delete operation: " + dir.getAbsolutePath());
|
||||||
|
}
|
||||||
|
} catch (SecurityException ex) {
|
||||||
|
throw new IOException("Security error during recursive delete operation", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user