Compare commits

...

19 Commits

Author SHA1 Message Date
Johannes Frohnmeyer 4b831cb6a1
chore: update to 1.20.5
ci/woodpecker/push/jfmod Pipeline was successful Details
ci/woodpecker/tag/jfmod Pipeline was successful Details
2024-04-25 22:26:50 +02:00
Johannes Frohnmeyer cada2e99cd
chore: update to 1.20.4
ci/woodpecker/push/jfmod Pipeline was successful Details
2023-12-07 20:28:57 +01:00
Johannes Frohnmeyer e6aab9cd19
chore: update to 1.20.2
ci/woodpecker/push/jfmod Pipeline was successful Details
2023-09-22 20:37:51 +02:00
Johannes Frohnmeyer 8409042838
chore: add @reason javadoc to @Overwrite 2023-09-22 20:35:43 +02:00
Johannes Frohnmeyer e83d98fdec
chore: use proper default
ci/woodpecker/push/jfmod Pipeline was successful Details
2023-09-10 06:52:06 +02:00
Johannes Frohnmeyer 3b91be9864
chore: use jfMod DSL 2023-09-10 06:52:03 +02:00
Johannes Frohnmeyer 02ce4ef490
chore: simplify config 2023-09-10 06:51:59 +02:00
Johannes Frohnmeyer 423049ea7a
Bump to 1.20
ci/woodpecker/push/jfmod Pipeline was successful Details
ci/woodpecker/tag/jfmod Pipeline was successful Details
2023-06-09 18:23:12 +02:00
Johannes Frohnmeyer 3e3f0a394d
Bump to 1.19.4
ci/woodpecker/push/jfmod Pipeline failed Details
ci/woodpecker/tag/jfmod Pipeline was successful Details
2023-03-14 21:18:06 +01:00
Johannes Frohnmeyer b70b3c7d2a
Use new config compiler
ci/woodpecker/push/jfmod Pipeline was successful Details
2022-12-29 16:13:26 +01:00
Johannes Frohnmeyer 773d9a12bb
Update to 1.19.3
ci/woodpecker/push/jfmod Pipeline was successful Details
ci/woodpecker/tag/jfmod Pipeline was successful Details
2022-12-07 21:47:57 +01:00
Johannes Frohnmeyer a3bd03c260
Fix maven group
ci/woodpecker/push/jfmod Pipeline was successful Details
2022-12-03 19:46:31 +01:00
Johannes Frohnmeyer 023e2bda2a
Update to new infrastructure
ci/woodpecker/manual/jfmod Pipeline was successful Details
2022-12-02 16:30:22 +01:00
Johannes Frohnmeyer b3df3a6bd4
Update to LibJF 3 2022-08-28 16:59:26 +02:00
Johannes Frohnmeyer 3fdfc097cb
Use quickmath as the mod id for consistency 2022-08-21 16:22:54 +02:00
Johannes Frohnmeyer c80a2105e3
Update modrinth dependency names 2 2022-07-28 10:26:06 +02:00
Johannes Frohnmeyer 3b193d9349
Update modrinth dependency names 2022-07-28 10:24:54 +02:00
Johannes Frohnmeyer fa61d24e96
Update for 1.19.1 2022-07-28 10:21:07 +02:00
Johannes Frohnmeyer 6af5a0d9cd
Update for 1.19 2022-06-08 11:18:34 +02:00
26 changed files with 480 additions and 325 deletions

View File

@ -1,2 +0,0 @@
include:
- remote: 'https://jfmods.gitlab.io/scripts/jfmod.yml'

1
.woodpecker.yml Normal file
View File

@ -0,0 +1 @@
#link https://pages.frohnmeyer-wds.de/scripts/jfmod.yml

View File

@ -1,6 +1,7 @@
Quickmeth allows you to break math methods in minecraft by enabling replacements for:
Quickth allows you to break math methods in minecraft by enabling replacements for:
- The standard math methods (used almost everywhere where math is needed)
- Trigonometry (which is also used across the codebase and affect things like rendering)
- Perlin & Simplex noise methods (used in terrain generation)
WARNING: These replacements are intended to corrupt things and should not be used in worlds you care about
WARNING: These replacements are intended to corrupt things and should not be used in worlds you care about!
The "Corrupt more generic math" option might even prevent your game from loading incompletely generated worlds at all.

View File

@ -1,14 +0,0 @@
apply from: "https://jfmods.gitlab.io/scripts/jfmod.gradle"
dependencies {
modRuntimeOnly "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
include modImplementation("io.gitlab.jfronny.libjf:libjf-config-v0:${project.jfapi_version}")
include modImplementation("io.gitlab.jfronny.libjf:libjf-unsafe-v0:${project.jfapi_version}")
include("io.gitlab.jfronny.libjf:libjf-base:${project.jfapi_version}")
modRuntimeOnly("io.gitlab.jfronny.libjf:libjf-devutil-v0:${project.jfapi_version}")
modImplementation "com.terraformersmc:modmenu:3.1.0"
include modRuntimeOnly('io.gitlab.jfronny:gson:2.9.0.2022.4.2.19.45.43') // Dependency of LibJF 2.7.0
}

39
build.gradle.kts Normal file
View File

@ -0,0 +1,39 @@
plugins {
id("jfmod") version "1.6-SNAPSHOT"
}
allprojects { group = "io.gitlab.jfronny" }
base.archivesName = "quickmath"
jfMod {
minecraftVersion = "1.20.5"
yarn("build.1")
loaderVersion = "0.15.10"
libJfVersion = "3.15.5"
fabricApiVersion = "0.97.6+1.20.5"
modrinth {
projectId = "quickmath"
requiredDependencies.add("libjf")
optionalDependencies.add("modmenu")
}
curseforge {
projectId = "400837"
requiredDependencies.add("libjf")
optionalDependencies.add("modmenu")
}
}
dependencies {
modImplementation("io.gitlab.jfronny.libjf:libjf-config-core-v2")
modImplementation("io.gitlab.jfronny.libjf:libjf-unsafe-v0")
// Dev env
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-config-ui-tiny")
modLocalRuntime("io.gitlab.jfronny.libjf:libjf-devutil")
modLocalRuntime("com.terraformersmc:modmenu:10.0.0-beta.1")
// for modmenu
modLocalRuntime("net.fabricmc.fabric-api:fabric-resource-loader-v0")
modLocalRuntime("net.fabricmc.fabric-api:fabric-screen-api-v1")
modLocalRuntime("net.fabricmc.fabric-api:fabric-key-binding-api-v1")
}

View File

@ -1,14 +0,0 @@
# https://fabricmc.net/develop/
minecraft_version=1.18.2
yarn_mappings=build.2
loader_version=0.13.3
maven_group=io.jfronny.gitlab
archives_base_name=quickmeth
fabric_version=0.48.0+1.18.2
jfapi_version=2.7.1
modrinth_id=hRVfXPJj
modrinth_optional_dependencies=mOgUt4GM
curseforge_id=400837
curseforge_optional_dependencies=modmenu

9
settings.gradle.kts Normal file
View File

@ -0,0 +1,9 @@
pluginManagement {
repositories {
maven("https://maven.fabricmc.net/") // FabricMC
maven("https://maven.frohnmeyer-wds.de/artifacts") // scripts
gradlePluginPortal()
}
}
rootProject.name = "quickmath"

View File

@ -0,0 +1,139 @@
package io.gitlab.jfronny.quickmath;
import io.gitlab.jfronny.libjf.unsafe.asm.AsmConfig;
import io.gitlab.jfronny.libjf.unsafe.asm.AsmTransformer;
import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch;
import io.gitlab.jfronny.libjf.unsafe.asm.patch.PatchUtil;
import org.objectweb.asm.*;
import org.objectweb.asm.tree.*;
import java.util.Map;
import java.util.Set;
public class BytecodeTransformer implements AsmConfig {
private static final String math = "java/lang/Math";
private static final String random = "java/util/Random";
private static final String mathUtil = "io/gitlab/jfronny/quickmath/MathUtil";
private static final String mathHelperIntermediary = "net.minecraft.class_3532";
private static final String mathHelper = PatchUtil.mapClassNameInternal(mathHelperIntermediary);
private static final String mojangRandomIntermediary = "net.minecraft.class_5819";
private static final String mojangRandom = PatchUtil.mapClassNameInternal(mojangRandomIntermediary);
private static final String mathHelperRandomUuid = mth("method_15378", "(Lnet/minecraft/class_5819;)Ljava/util/UUID;");
private static final Map<String, String> mth = DMap.of( // Maps methods in mathHelper to QuickMäth MathUtil methods
mth("method_15374", "(F)F"), "sinM",
mth("method_15362", "(F)F"), "cosM",
mth("method_15355", "(F)F"), "sqrtM",
mth("method_15375", "(D)I"), "floor"
);
private static final Map<String, String> rnd = DMap.of( // Maps methods in Minecraft Random to QuickMäth MathUtil methods
rnd("method_43054", "()I"), "nextInt",
rnd("method_43048", "(I)I"), "nextInt",
rnd("method_43055", "()J"), "nextLong",
rnd("method_43056", "()Z"), "nextBoolean",
rnd("method_43057", "()F"), "nextFloat",
rnd("method_43058", "()D"), "random",
rnd("method_43059", "()D"), "random"
);
private static final Map<String, Boolean> stat = Map.of( // Maps QuickMäth MathUtil methods to booleans representing whether to overwrite them
"sin", Cfg.corruptTrigonometry.contains(Cfg.CorruptionLevel2.FULL),
"cos", Cfg.corruptTrigonometry.contains(Cfg.CorruptionLevel2.FULL),
"sinM", Cfg.corruptTrigonometry.contains(Cfg.CorruptionLevel2.MAJOR),
"cosM", Cfg.corruptTrigonometry.contains(Cfg.CorruptionLevel2.MAJOR),
//"sqrt", Cfg.corruptGenericMath.contains(Cfg.CorruptionLevel2.MAJOR),
"sqrtM", Cfg.corruptGenericMath.contains(Cfg.CorruptionLevel2.MAJOR),
//"floor", Cfg.corruptGenericMath.contains(Cfg.CorruptionLevel2.FULL),
// "nextInt", Cfg.corruptGenericMath.contains(Cfg.CorruptionLevel2.FULL),
"nextLong", Cfg.corruptGenericMath.contains(Cfg.CorruptionLevel2.FULL),
"nextBoolean", Cfg.corruptGenericMath.contains(Cfg.CorruptionLevel2.FULL),
// "nextFloat", Cfg.corruptGenericMath.contains(Cfg.CorruptionLevel2.FULL),
"random", Cfg.corruptGenericMath.contains(Cfg.CorruptionLevel2.FULL)
);
private static String mth(String method, String descriptor) {
return PatchUtil.mapMethodName(mathHelperIntermediary, method, descriptor);
}
private static String rnd(String method, String descriptor) {
return PatchUtil.mapMethodName(mojangRandomIntermediary, method, descriptor);
}
@Override
public Set<String> skipClasses() {
return null;
}
@Override
public Set<Patch> getPatches() {
return Set.of(this::patchInvokes);
}
private void patchInvokes(ClassNode klazz) {
for (MethodNode method : klazz.methods) {
if (klazz.name.equals(mathHelper) && method.name.equals(mathHelperRandomUuid)) { // UUIDs still need to work
if (Cfg.debugAsm) {
ModMain.LOGGER.info("Skipped replacing method calls in MathHelper.randomUuid");
}
continue;
}
for (AbstractInsnNode insn : method.instructions.toArray()) {
if (insn.getOpcode() == Opcodes.INVOKESTATIC || insn.getOpcode() == Opcodes.INVOKEVIRTUAL || insn.getOpcode() == Opcodes.INVOKEINTERFACE) {
String insNew = null;
MethodInsnNode mIns = (MethodInsnNode) insn;
// Resolve a possible replacement method in QuickMäth MathUtil
if (mIns.owner.equals(math)) {
if (stat.containsKey(mIns.name))
insNew = mIns.name;
} else if (mIns.owner.equals(mathHelper)) {
if (mth.containsKey(mIns.name))
insNew = mth.get(mIns.name);
} else if (mIns.owner.equals(mojangRandom)) {
if (rnd.containsKey(mIns.name))
insNew = rnd.get(mIns.name);
} else if (mIns.owner.equals(random)) {
insNew = switch (mIns.name) {
case "nextInt" -> "nextInt";
case "nextLong" -> "nextLong";
case "nextBoolean" -> "nextBoolean";
case "nextFloat" -> "nextFloat";
case "nextDouble", "nextGaussian" -> "random";
default -> null;
};
}
// Check whether the method should be replaced
if (!klazz.name.equals(mathUtil) && insNew != null && stat.containsKey(insNew) && stat.get(insNew)) {
String originalOwner = mIns.owner;
String originalName = mIns.name;
// Pop the instance when calling an instance method
if (mIns.getOpcode() != Opcodes.INVOKESTATIC) {
Type[] params = Type.getArgumentTypes(mIns.desc);
// This implementation only works with 0 or 1 parameters of category 1 computational types
// This means that doubles and longs are unsupported
if (params.length > 1)
throw new IllegalArgumentException("The quickmeth bytecode transformer does not support more than one argument");
for (Type param : params) {
if (param.getSize() != 1)
throw new IllegalStateException("The quickmeth bytecode transformer only supports category 1 computational types");
}
// If a parameter is present, swap the object to the top, then pop
if (params.length == 1)
method.instructions.insertBefore(mIns, new InsnNode(Opcodes.SWAP));
// Pop the object instance, leaving the parameter if it exists
method.instructions.insertBefore(mIns, new InsnNode(Opcodes.POP));
}
// Invoke the static method
mIns.setOpcode(Opcodes.INVOKESTATIC);
mIns.owner = mathUtil;
mIns.name = insNew;
mIns.itf = false;
if (Cfg.debugAsm) {
ModMain.LOGGER.info("Replaced call to L" + originalOwner + ";" + originalName + mIns.desc
+ " in " + klazz.name
+ " with L" + mIns.owner + ";" + mIns.name + mIns.desc);
}
}
}
}
}
}
}

View File

@ -0,0 +1,45 @@
package io.gitlab.jfronny.quickmath;
import io.gitlab.jfronny.libjf.config.api.v2.Entry;
import io.gitlab.jfronny.libjf.config.api.v2.JfConfig;
import io.gitlab.jfronny.libjf.config.api.v2.dsl.ConfigBuilder;
import io.gitlab.jfronny.libjf.config.api.v2.dsl.Migration;
@JfConfig(tweaker = Cfg.Migrations.class)
public class Cfg {
@Entry public static CorruptionLevel2 corruptGenericMath = CorruptionLevel2.MAJOR;
@Entry public static CorruptionLevel2 corruptTrigonometry = CorruptionLevel2.FULL;
@Entry public static boolean corruptPerlinNoise = true;
@Entry public static boolean corruptSimplexNoise = true;
@Entry public static boolean debugAsm = false;
static {
JFC_Cfg.ensureInitialized();
}
public enum CorruptionLevel {
DISABLED, MINOR, MAJOR, FULL;
public boolean contains(CorruptionLevel level) {
return compareTo(level) >= 0;
}
}
public enum CorruptionLevel2 {
DISABLED, MAJOR, FULL;
public boolean contains(CorruptionLevel2 level) {
return compareTo(level) >= 0;
}
}
public static class Migrations {
public static ConfigBuilder<?> tweak(ConfigBuilder<?> builder) {
return builder.addMigration("corruptGenericMath2", Migration.of(reader -> {
if (reader.nextBoolean()) corruptGenericMath = CorruptionLevel2.FULL;
})).addMigration("corruptTrigonometry2", Migration.of(reader -> {
if (!reader.nextBoolean()) corruptTrigonometry = CorruptionLevel2.MAJOR;
}));
}
}
}

View File

@ -0,0 +1,75 @@
package io.gitlab.jfronny.quickmath;
import java.util.*;
/** Creates a map that deduplicates keys using the Map.of() syntax */
public class DMap {
static <K, V> Map<K, V> of() {
return Map.of();
}
static <K, V> Map<K, V> of(K k1, V v1) {
return Map.of(k1, v1);
}
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
return createMulti(e(k1, v1), e(k2, v2));
}
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
return createMulti(e(k1, v1), e(k2, v2), e(k3, v3));
}
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
return createMulti(e(k1, v1), e(k2, v2), e(k3, v3), e(k4, v4));
}
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
return createMulti(e(k1, v1), e(k2, v2), e(k3, v3), e(k4, v4), e(k5, v5));
}
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) {
return createMulti(e(k1, v1), e(k2, v2), e(k3, v3), e(k4, v4), e(k5, v5), e(k6, v6));
}
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) {
return createMulti(e(k1, v1), e(k2, v2), e(k3, v3), e(k4, v4), e(k5, v5), e(k6, v6), e(k7, v7));
}
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8) {
return createMulti(e(k1, v1), e(k2, v2), e(k3, v3), e(k4, v4), e(k5, v5), e(k6, v6), e(k7, v7), e(k8, v8));
}
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
return createMulti(e(k1, v1), e(k2, v2), e(k3, v3), e(k4, v4), e(k5, v5), e(k6, v6), e(k7, v7), e(k8, v8), e(k9, v9));
}
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
return createMulti(e(k1, v1), e(k2, v2), e(k3, v3), e(k4, v4), e(k5, v5), e(k6, v6), e(k7, v7), e(k8, v8), e(k9, v9), e(k10, v10));
}
private static <K, V> Map.Entry<K, V> e(K key, V value) {
return new Map.Entry<>() {
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V v) {
throw new UnsupportedOperationException();
}
};
}
private static <K, V> Map<K, V> createMulti(Map.Entry<K, V>... entries) {
Map<K, V> map = new HashMap<>();
for (Map.Entry<K, V> entry : entries) map.put(entry.getKey(), entry.getValue());
return Map.copyOf(map);
}
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.quickmeth;
package io.gitlab.jfronny.quickmath;
import net.minecraft.util.math.MathHelper;
@ -77,7 +77,7 @@ public class MathUtil {
return 2;
}
public static int nextInt(int bound) {
return Math.min(2, bound);
return Math.min(2, bound - 1);
}
public static long nextLong() {
return 2;

View File

@ -1,15 +1,14 @@
package io.gitlab.jfronny.quickmeth;
package io.gitlab.jfronny.quickmath;
import io.gitlab.jfronny.quickmeth.mixin.*;
import org.objectweb.asm.tree.ClassNode;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import java.util.List;
import java.util.Objects;
import java.util.Set;
public class MixinPlugin implements IMixinConfigPlugin {
private static final String PREFIX = "io.gitlab.jfronny.quickmath.mixin.";
@Override
public void onLoad(String mixinPackage) {
@ -20,19 +19,17 @@ public class MixinPlugin implements IMixinConfigPlugin {
return null;
}
@SuppressWarnings("ReferenceToMixin")
@Override
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
if (Objects.equals(mixinClassName, MathHelperMixin.class.getName()))
return Cfg.corruptGenericMath;
else if (Objects.equals(mixinClassName, MathHelperMixin2.class.getName()))
return Cfg.corruptGenericMath2;
else if (Objects.equals(mixinClassName, MixinPerlinNoiseSampler.class.getName()))
return Cfg.corruptPerlinNoise;
else if (Objects.equals(mixinClassName, MixinSimplexNoiseSampler.class.getName()))
return Cfg.corruptSimplexNoise;
else
throw new IllegalStateException("Unrecognized mixin! This should never happen");
if (!mixinClassName.startsWith(PREFIX))
throw new IllegalStateException("Unrecognized mixin! This should never happen: " + mixinClassName);
return switch (mixinClassName.substring(PREFIX.length())) {
case "MathHelperMixin" -> Cfg.corruptGenericMath.contains(Cfg.CorruptionLevel2.MAJOR);
case "MathHelperMixin2" -> Cfg.corruptGenericMath.contains(Cfg.CorruptionLevel2.FULL);
case "MixinPerlinNoiseSampler" -> Cfg.corruptPerlinNoise;
case "MixinSimplexNoiseSampler" -> Cfg.corruptSimplexNoise;
default -> throw new IllegalStateException("Unrecognized mixin! This should never happen: " + mixinClassName);
};
}
@Override

View File

@ -0,0 +1,12 @@
package io.gitlab.jfronny.quickmath;
import io.gitlab.jfronny.commons.logger.SystemLoggerPlus;
import net.fabricmc.api.*;
public class ModMain implements ModInitializer {
public static final SystemLoggerPlus LOGGER = SystemLoggerPlus.forName("quickmäth");
@Override
public void onInitialize() {
LOGGER.info("QuickMäth initialized, but why are you using this?");
}
}

View File

@ -0,0 +1,62 @@
package io.gitlab.jfronny.quickmath.mixin;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.random.Random;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(MathHelper.class)
public abstract class MathHelperMixin {
@Shadow @Final private static Random RANDOM;
@Shadow public static int floor(double value) { return 0; }
@Shadow public static double nextDouble(Random random, double min, double max) { return 0; }
/**
* @author JFronny
* @reason Reduce precision
*/
@Overwrite
public static long lfloor(double d) {
return (long) (Math.floor(d / 4) * 4);
}
/**
* @author JFronny
* @reason Introduce variation
*/
@Overwrite
public static double absMax(double d, double e) {
if (d > 0.0D) {
d = -d;
}
if (e > 0.0D) {
e = -e;
}
if (e < -16)
e += 3;
return -1 - Math.max(d, e);
}
@ModifyVariable(method = "nextInt(Lnet/minecraft/util/math/random/Random;II)I", at = @At("HEAD"), argsOnly = true, ordinal = 0)
private static int adjustRandomDoubleParam(int min) {
return Math.max(min - 1, 0);
}
@Inject(method = "nextFloat(Lnet/minecraft/util/math/random/Random;FF)F", at = @At("TAIL"), cancellable = true)
private static void adjustRandomFloat(CallbackInfoReturnable<Float> ci) {
ci.setReturnValue(ci.getReturnValue() * 0.9f);
}
@ModifyVariable(method = "nextDouble(Lnet/minecraft/util/math/random/Random;DD)D", at = @At("HEAD"), argsOnly = true, ordinal = 0)
private static double adjustRandomDoubleParam(double min) {
return min - 1;
}
@Inject(method = "nextDouble(Lnet/minecraft/util/math/random/Random;DD)D", at = @At("TAIL"), cancellable = true)
private static void adjustRandomDouble(CallbackInfoReturnable<Double> ci) {
ci.setReturnValue((double) floor(ci.getReturnValue()));
}
}

View File

@ -1,6 +1,6 @@
package io.gitlab.jfronny.quickmeth.mixin;
package io.gitlab.jfronny.quickmath.mixin;
import io.gitlab.jfronny.quickmeth.MathUtil;
import io.gitlab.jfronny.quickmath.MathUtil;
import net.minecraft.util.math.MathHelper;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

View File

@ -1,6 +1,6 @@
package io.gitlab.jfronny.quickmeth.mixin;
package io.gitlab.jfronny.quickmath.mixin;
import io.gitlab.jfronny.quickmeth.MathUtil;
import io.gitlab.jfronny.quickmath.MathUtil;
import net.minecraft.util.math.noise.PerlinNoiseSampler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@ -10,35 +10,43 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PerlinNoiseSampler.class)
public abstract class MixinPerlinNoiseSampler {
@ModifyVariable(method = "sample(IIIDDDD)D", at = @At("HEAD"), argsOnly = true, ordinal = 0)
@ModifyVariable(method = "sample(IIIDDDD)D", at = @At("HEAD"), argsOnly = true, index = 4)
private double sampleAdjustX(double localX) {
return MathUtil.boxedInvert(localX);
}
@ModifyVariable(method = "sampleDerivative(IIIDDD[D)D", at = @At("HEAD"), argsOnly = true, ordinal = 0)
private double derivAdjustX(double localX) {
return MathUtil.boxedInvert(localX);
@ModifyVariable(method = "sample(IIIDDDD)D", at = @At("HEAD"), argsOnly = true, index = 6)
private double sampleAdjustY(double localY) {
return MathUtil.boxedInvert(localY);
}
//Once again, the y parameter is ignored because mixin
@ModifyVariable(method = "sample(IIIDDDD)D", at = @At("HEAD"), argsOnly = true, ordinal = 2)
@ModifyVariable(method = "sample(IIIDDDD)D", at = @At("HEAD"), argsOnly = true, index = 8)
private double sampleAdjustZ(double localZ) {
return MathUtil.boxedInvert(localZ);
}
@ModifyVariable(method = "sampleDerivative(IIIDDD[D)D", at = @At("HEAD"), argsOnly = true, ordinal = 2)
@Inject(method = "sample(IIIDDDD)D", at = @At("TAIL"), cancellable = true)
private void sampleAdjustResult(CallbackInfoReturnable<Double> ret) {
ret.setReturnValue(MathUtil.boxedInvert(ret.getReturnValue()));
}
@ModifyVariable(method = "sampleDerivative(IIIDDD[D)D", at = @At("HEAD"), argsOnly = true, index = 4)
private double derivAdjustX(double localX) {
return MathUtil.boxedInvert(localX);
}
@ModifyVariable(method = "sampleDerivative(IIIDDD[D)D", at = @At("HEAD"), argsOnly = true, index = 6)
private double derivAdjustY(double localY) {
return MathUtil.boxedInvert(localY);
}
@ModifyVariable(method = "sampleDerivative(IIIDDD[D)D", at = @At("HEAD"), argsOnly = true, index = 8)
private double derivAdjustZ(double localZ) {
return MathUtil.boxedInvert(localZ);
}
@Inject(method = "sample(IIIDDDD)D", at = @At("TAIL"), cancellable = true)
private void sampleAsjustResult(CallbackInfoReturnable<Double> ret) {
ret.setReturnValue(MathUtil.boxedInvert(ret.getReturnValue()));
}
@Inject(method = "sampleDerivative(IIIDDD[D)D", at = @At("TAIL"), cancellable = true)
private void derivAsjustResult(CallbackInfoReturnable<Double> ret) {
private void derivAdjustResult(CallbackInfoReturnable<Double> ret) {
ret.setReturnValue(MathUtil.boxedInvert(ret.getReturnValue()));
}
}

View File

@ -1,6 +1,6 @@
package io.gitlab.jfronny.quickmeth.mixin;
package io.gitlab.jfronny.quickmath.mixin;
import io.gitlab.jfronny.quickmeth.MathUtil;
import io.gitlab.jfronny.quickmath.MathUtil;
import net.minecraft.util.math.noise.SimplexNoiseSampler;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@ -15,23 +15,32 @@ public abstract class MixinSimplexNoiseSampler {
ret.setReturnValue(MathUtil.boxedInvert(ret.getReturnValue()));
}
@ModifyVariable(method = "sample(DD)D", at = @At("HEAD"), argsOnly = true, ordinal = 0)
@ModifyVariable(method = "sample(DD)D", at = @At("HEAD"), argsOnly = true, index = 1)
private double sampleAdjustX(double x) {
return MathUtil.boxedInvert(x);
}
// The y parameter is ignored here because otherwise this will crash. I don't know why.
@Inject(method = "getGradient(I)I", at = @At("TAIL"), cancellable = true)
private void gradientAdjust(CallbackInfoReturnable<Integer> ret) {
@ModifyVariable(method = "sample(DD)D", at = @At("HEAD"), argsOnly = true, index = 3)
private double sampleAdjustY(double y) {
return MathUtil.boxedInvert(y);
}
@Inject(method = "map(I)I", at = @At("TAIL"), cancellable = true)
private void mapAdjust(CallbackInfoReturnable<Integer> ret) {
ret.setReturnValue(ret.getReturnValue() & 255);
}
@ModifyVariable(method = "grad(IDDDD)D", at = @At("HEAD"), argsOnly = true, ordinal = 0)
@ModifyVariable(method = "grad(IDDDD)D", at = @At("HEAD"), argsOnly = true, index = 2)
private double gradAdjustX(double x) {
return MathUtil.boxedInvert(x);
}
// The y parameter is ignored here because otherwise this will crash. I don't know why.
@ModifyVariable(method = "grad(IDDDD)D", at = @At("HEAD"), argsOnly = true, ordinal = 2)
@ModifyVariable(method = "grad(IDDDD)D", at = @At("HEAD"), argsOnly = true, index = 4)
private double gradAdjustY(double y) {
return MathUtil.boxedInvert(y);
}
@ModifyVariable(method = "grad(IDDDD)D", at = @At("HEAD"), argsOnly = true, index = 6)
private double gradAdjustZ(double z) {
return MathUtil.boxedInvert(z);
}

View File

@ -1,91 +0,0 @@
package io.gitlab.jfronny.quickmeth;
import io.gitlab.jfronny.libjf.unsafe.asm.AsmConfig;
import io.gitlab.jfronny.libjf.unsafe.asm.AsmTransformer;
import io.gitlab.jfronny.libjf.unsafe.asm.patch.Patch;
import io.gitlab.jfronny.libjf.unsafe.asm.patch.PatchUtil;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import java.util.Map;
import java.util.Set;
public class BytecodeTransformer implements AsmConfig, Patch {
private static final String math = "java/lang/Math";
private static final String random = "java/util/Random";
private static final String mathUtil = "io/gitlab/jfronny/quickmeth/MathUtil";
private static final String mathHelperIntermediary = "net.minecraft.class_3532";
private static final String mathHelper = PatchUtil.getRemappedInternal(mathHelperIntermediary);
private static final Map<String, String> mth = Map.of(
mth("method_15374", "(F)F"), "sinM",
mth("method_15362", "(F)F"), "cosM",
mth("method_15355", "(F)F"), "sqrtM"
//mth("method_15375", "(D)I"), "floor"
);
private static final Map<String, Boolean> stat = Map.of(
"sin", Cfg.corruptTrigonometry2,
"cos", Cfg.corruptTrigonometry2,
"sinM", Cfg.corruptTrigonometry,
"cosM", Cfg.corruptTrigonometry,
//"sqrt", Cfg.corruptGenericMath,
"sqrtM", Cfg.corruptGenericMath,
//"floor", Cfg.corruptGenericMath2,
"random", Cfg.corruptGenericMath2
);
private static String mth(String method, String descriptor) {
return AsmTransformer.MAPPING_RESOLVER.mapMethodName(AsmTransformer.INTERMEDIARY, mathHelperIntermediary, method, descriptor);
}
@Override
public Set<String> skipClasses() {
return null;
}
@Override
public Set<Patch> getPatches() {
return Set.of(this);
}
@Override
public void apply(ClassNode klazz) {
for (MethodNode method : klazz.methods) {
for (AbstractInsnNode insn : method.instructions.toArray()) {
if (insn.getOpcode() == Opcodes.INVOKESTATIC || insn.getOpcode() == Opcodes.INVOKEVIRTUAL) {
String insNew = null;
MethodInsnNode mIns = (MethodInsnNode) insn;
if (mIns.owner.equals(math)) {
if (stat.containsKey(mIns.name) && stat.get(mIns.name))
insNew = mIns.name;
}
else if (mIns.owner.equals(mathHelper)) {
if (mth.containsKey(mIns.name)) {
insNew = mth.get(mIns.name);
if (!stat.get(insNew))
insNew = null;
}
}
else if (mIns.owner.equals(random)) {
if (Cfg.corruptGenericMath2 && !klazz.name.equals(mathUtil)) {
insNew = switch (mIns.name) {
//case "nextInt" -> "nextInt";
case "nextLong" -> "nextLong";
case "nextBoolean" -> "nextBoolean";
//case "nextFloat" -> "nextFloat";
case "nextDouble", "nextGaussian" -> "random";
default -> null;
};
}
}
if (insNew != null) {
if (mIns.getOpcode() == Opcodes.INVOKEVIRTUAL)
method.instructions.insertBefore(mIns, new InsnNode(Opcodes.POP));
mIns.setOpcode(Opcodes.INVOKESTATIC);
mIns.owner = mathUtil;
mIns.name = insNew;
}
}
}
}
}
}

View File

@ -1,19 +0,0 @@
package io.gitlab.jfronny.quickmeth;
import io.gitlab.jfronny.libjf.config.api.Entry;
import io.gitlab.jfronny.libjf.config.api.JfConfig;
public class Cfg implements JfConfig {
@Entry
public static Boolean corruptGenericMath = true;
@Entry
public static Boolean corruptGenericMath2 = false;
@Entry
public static Boolean corruptTrigonometry = true;
@Entry
public static Boolean corruptTrigonometry2 = true;
@Entry
public static Boolean corruptPerlinNoise = true;
@Entry
public static Boolean corruptSimplexNoise = true;
}

View File

@ -1,13 +0,0 @@
package io.gitlab.jfronny.quickmeth;
import net.fabricmc.api.ModInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ModMain implements ModInitializer {
public static final Logger LOGGER = LoggerFactory.getLogger("quickmäth");
@Override
public void onInitialize() {
LOGGER.info("QuickMäth initialized, but why are you using this?");
}
}

View File

@ -1,91 +0,0 @@
package io.gitlab.jfronny.quickmeth.mixin;
import io.gitlab.jfronny.quickmeth.MathUtil;
import net.minecraft.util.math.MathHelper;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Random;
@Mixin(MathHelper.class)
public abstract class MathHelperMixin {
@Shadow @Final private static Random RANDOM;
@Shadow public static int floor(double value) { return 0; }
@Shadow public static double nextDouble(Random random, double min, double max) { return 0; }
@Overwrite
public static int fastFloor(double d) {
return (int)(d / 32) * 32;
}
@Overwrite
public static long lfloor(double d) {
return (long) (Math.floor(d / 4) * 4);
}
@Overwrite
public static double absMax(double d, double e) {
if (d > 0.0D) {
d = -d;
}
if (e > 0.0D) {
e = -e;
}
if (e < -16)
e += 3;
return -1 - Math.max(d, e);
}
@ModifyVariable(method = "nextInt(Ljava/util/Random;II)I", at = @At("HEAD"), argsOnly = true, ordinal = 0)
private static int adjustRandomDoubleParam(int min) {
return Math.max(min - 1, 0);
}
@Inject(method = "nextFloat(Ljava/util/Random;FF)F", at = @At("TAIL"), cancellable = true)
private static void adjustRandomFloat(CallbackInfoReturnable<Float> ci) {
ci.setReturnValue(ci.getReturnValue() * 0.9f);
}
@ModifyVariable(method = "nextDouble(Ljava/util/Random;DD)D", at = @At("HEAD"), argsOnly = true, ordinal = 0)
private static double adjustRandomDoubleParam(double min) {
return min - 1;
}
@Inject(method = "nextDouble(Ljava/util/Random;DD)D", at = @At("TAIL"), cancellable = true)
private static void adjustRandomDouble(CallbackInfoReturnable<Double> ci) {
ci.setReturnValue((double) floor(ci.getReturnValue()));
}
@Overwrite
public static double average(long[] array) {
long[] var3 = array;
long min = Long.MAX_VALUE;
long max = Long.MIN_VALUE;
int var4 = array.length;
for(int var5 = 0; var5 < var4; ++var5) {
long m = var3[var5];
if (m > max)
max = m;
if (m < min)
min = m;
}
return nextDouble(RANDOM, min, max);
}
@Overwrite
public static long clamp(long value, long min, long max) {
return MathUtil.boxedInvert(Math.max(Math.min(value, max), min), max, min);
}
}

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,21 @@
{
"quickmath.jfconfig.title": "QuickMäth",
"quickmath.jfconfig.tooltip": "Restart to apply changes",
"quickmath.jfconfig.corruptGenericMath": "Corrupt generic math",
"quickmath.jfconfig.corruptGenericMath.tooltip": "Corrupts methods in MathHelper. This will impact many things but most notably movement",
"quickmath.jfconfig.corruptTrigonometry": "Corrupt Trigonometry",
"quickmath.jfconfig.corruptTrigonometry.tooltip": "Corrupts trigonometry methods. Effects vary",
"quickmath.jfconfig.corruptPerlinNoise": "Corrupt perlin noise",
"quickmath.jfconfig.corruptPerlinNoise.tooltip": "Corrupts methods in OctavePerlinNoiseSampler and PerlinNoiseSampler. This will mostly impact world generation",
"quickmath.jfconfig.corruptSimplexNoise": "Corrupt simplex noise",
"quickmath.jfconfig.corruptSimplexNoise.tooltip": "Corrupts methods in SimplexNoiseSampler. I am actually not sure what this breaks",
"quickmath.jfconfig.debugAsm": "Debug ASM",
"quickmath.jfconfig.debugAsm.tooltip": "Prints debug messages for the purpose of debugging",
"quickmath.jfconfig.enum.CorruptionLevel2.DISABLED": "Disabled",
"quickmath.jfconfig.enum.CorruptionLevel2.MAJOR": "Major",
"quickmath.jfconfig.enum.CorruptionLevel2.FULL": "Full",
"quickmath.jfconfig.enum.CorruptionLevel.DISABLED": "Disabled",
"quickmath.jfconfig.enum.CorruptionLevel.MINOR": "Minor",
"quickmath.jfconfig.enum.CorruptionLevel.MAJOR": "Major",
"quickmath.jfconfig.enum.CorruptionLevel.FULL": "Full"
}

View File

@ -1,15 +0,0 @@
{
"quickmeth.jfconfig.title": "QuickMäth",
"quickmeth.jfconfig.corruptGenericMath": "Corrupt generic math",
"quickmeth.jfconfig.corruptGenericMath.tooltip": "Corrupts methods in MathHelper. This will impact many things but most notably movement",
"quickmeth.jfconfig.corruptGenericMath2": "Corrupt more generic math",
"quickmeth.jfconfig.corruptGenericMath2.tooltip": "Corrupts more methods in MathHelper. These WILL break a lot of things so they are separate",
"quickmeth.jfconfig.corruptTrigonometry": "Corrupt Trigonometry",
"quickmeth.jfconfig.corruptTrigonometry.tooltip": "Corrupts trigonometry methods. Effects vary",
"quickmeth.jfconfig.corruptTrigonometry2": "Corrupt more Trigonometry",
"quickmeth.jfconfig.corruptTrigonometry2.tooltip": "Corrupts all trigonometry methods. This WILL break a lot of things",
"quickmeth.jfconfig.corruptPerlinNoise": "Corrupt perlin noise",
"quickmeth.jfconfig.corruptPerlinNoise.tooltip": "Corrupts methods in OctavePerlinNoiseSampler and PerlinNoiseSampler. This will mostly impact world generation",
"quickmeth.jfconfig.corruptSimplexNoise": "Corrupt simplex noise",
"quickmeth.jfconfig.corruptSimplexNoise.tooltip": "Corrupts methods in SimplexNoiseSampler. I am actually not sure what this breaks"
}

View File

@ -1,37 +1,33 @@
{
"schemaVersion": 1,
"id": "quickmeth",
"id": "quickmath",
"provides": ["quickmeth"],
"version": "${version}",
"name": "Quickmeth",
"description": "Replaces math methods with incorrect alternatives",
"name": "Quickth",
"description": "Replaces math methods with incorrect alternatives, causing interesting corruption",
"authors": [
"JFronny"
],
"contact": {
"website": "https://jfronny.gitlab.io",
"repo": "https://gitlab.com/jfmods/Quickmeth"
"email": "projects.contact@frohnmeyer-wds.de",
"homepage": "https://jfronny.gitlab.io",
"issues": "https://git.frohnmeyer-wds.de/JfMods/QuickMath/issues",
"sources": "https://git.frohnmeyer-wds.de/JfMods/QuickMath"
},
"license": "MIT",
"icon": "assets/quickmeth/icon.png",
"icon": "assets/quickmath/icon.png",
"environment": "*",
"entrypoints": {
"libjf:config": [
"io.gitlab.jfronny.quickmeth.Cfg"
],
"libjf:asm": [
"io.gitlab.jfronny.quickmeth.BytecodeTransformer"
],
"main": [
"io.gitlab.jfronny.quickmeth.ModMain"
]
"libjf:config": ["io.gitlab.jfronny.quickmath.JFC_Cfg"],
"libjf:asm": ["io.gitlab.jfronny.quickmath.BytecodeTransformer"],
"main": ["io.gitlab.jfronny.quickmath.ModMain"]
},
"mixins": [
"quickmeth.mixins.json"
],
"mixins": ["quickmath.mixins.json"],
"depends": {
"fabricloader": ">=0.13.3",
"minecraft": "*",
"libjf-config-v0": ">=2.7.1"
"libjf-config-core-v1": ">=2.10.0",
"libjf-unsafe-v0": ">=2.10.0"
},
"custom": {
"lithium:options": {

View File

@ -1,9 +1,9 @@
{
"required": true,
"minVersion": "0.8",
"package": "io.gitlab.jfronny.quickmeth.mixin",
"package": "io.gitlab.jfronny.quickmath.mixin",
"compatibilityLevel": "JAVA_17",
"plugin": "io.gitlab.jfronny.quickmeth.MixinPlugin",
"plugin": "io.gitlab.jfronny.quickmath.MixinPlugin",
"mixins": [
"MathHelperMixin",
"MathHelperMixin2",