From abc95ebd000ec159ccb4bc117888835b748ad7f2 Mon Sep 17 00:00:00 2001 From: zsawyer Date: Tue, 24 Jan 2023 19:41:46 +0100 Subject: [PATCH 1/3] adopt handedness conversion scheme from the fabric mod conversion scheme still converts Minecraft's a right-handed system to Mumble's left-handed system but using a different approach (switching z axis instead of previously swapping z and y axis) fixes #55 --- mod/build.gradle | 2 +- .../mods/mumblelink/mumble/UpdateData.java | 51 +++++++++++-------- 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/mod/build.gradle b/mod/build.gradle index 1d33662..f6f8213 100644 --- a/mod/build.gradle +++ b/mod/build.gradle @@ -18,7 +18,7 @@ apply plugin: 'net.minecraftforge.gradle' apply plugin: 'idea' apply plugin: 'maven-publish' -ext.modversion = "5.1.0" +ext.modversion = "6.0.0" ext.mcversion = "1.18.1" ext.forgeversion_dependency = "39" ext.forgeversion = "39.0.0" diff --git a/mod/src/main/java/zsawyer/mods/mumblelink/mumble/UpdateData.java b/mod/src/main/java/zsawyer/mods/mumblelink/mumble/UpdateData.java index 2620c16..d5c422b 100644 --- a/mod/src/main/java/zsawyer/mods/mumblelink/mumble/UpdateData.java +++ b/mod/src/main/java/zsawyer/mods/mumblelink/mumble/UpdateData.java @@ -100,65 +100,76 @@ public void set(Minecraft game) { // 1 unit = 1 meter // initialize multipliers + // converted to left-handed coordinate system + // (Mumble uses a left-handed, Minecraft uses a right-handed) + float fAvatarPositionX = 1; + float fAvatarPositionY = 1; + float fAvatarPositionZ = -1; // switch to left-handedness + + float fCameraPositionX = 1; + float fCameraPositionY = 1; + float fCameraPositionZ = -1; // switch to left-handedness + float fAvatarFrontX = 1; float fAvatarFrontY = 1; - float fAvatarFrontZ = 1; + float fAvatarFrontZ = -1; // switch to left-handedness float fCameraFrontX = 1; float fCameraFrontY = 1; - float fCameraFrontZ = 1; + float fCameraFrontZ = -1; // switch to left-handedness float fAvatarTopX = 1; - float fAvatarTopY = 1; // Y points up - float fAvatarTopZ = 1; + float fAvatarTopY = 1; + float fAvatarTopZ = -1; // switch to left-handedness float fCameraTopX = 1; - float fCameraTopY = 1; // Y points up - float fCameraTopZ = 1; + float fCameraTopY = 1; + float fCameraTopZ = -1; // switch to left-handedness Vec3 lookDirection = game.player.getLookAngle(); Vec3 topDirection = getTopVec(game); // Position of the avatar fAvatarPosition = new float[]{ - (float) game.player.getPosition(1f).x(), - (float) game.player.getPosition(1f).z(), - (float) game.player.getPosition(1f).y() + (float) game.player.getPosition(1f).x() * fAvatarPositionX, + (float) game.player.getPosition(1f).y() * fAvatarPositionY, + (float) game.player.getPosition(1f).z() * fAvatarPositionZ }; // Unit vector pointing out of the avatar's eyes (here Front looks // into scene). fAvatarFront = new float[]{ (float) lookDirection.x * fAvatarFrontX, - (float) lookDirection.z * fAvatarFrontZ, - (float) lookDirection.y * fAvatarFrontY + (float) lookDirection.y * fAvatarFrontY, + (float) lookDirection.z * fAvatarFrontZ }; // Unit vector pointing out of the top of the avatar's head (here // Top looks straight up). fAvatarTop = new float[]{ (float) topDirection.x * fAvatarTopX, - (float) topDirection.z * fAvatarTopZ, - (float) topDirection.y * fAvatarTopY + (float) topDirection.y * fAvatarTopY, + (float) topDirection.z * fAvatarTopZ }; // TODO: use real camera position, s.a. + // Position of the camera fCameraPosition = new float[]{ - (float) game.player.getPosition(1f).x(), - (float) game.player.getPosition(1f).z(), - (float) game.player.getPosition(1f).y() + (float) game.player.getPosition(1f).x() * fCameraPositionX, + (float) game.player.getPosition(1f).y() * fCameraPositionY, + (float) game.player.getPosition(1f).z() * fCameraPositionZ }; fCameraFront = new float[]{ (float) lookDirection.x * fCameraFrontX, - (float) lookDirection.z * fCameraFrontZ, - (float) lookDirection.y * fCameraFrontY + (float) lookDirection.y * fCameraFrontY, + (float) lookDirection.z * fCameraFrontZ }; fCameraTop = new float[]{ (float) topDirection.x * fCameraTopX, - (float) topDirection.z * fCameraTopZ, - (float) topDirection.y * fCameraTopY + (float) topDirection.y * fCameraTopY, + (float) topDirection.z * fCameraTopZ }; // Identifier which uniquely identifies a certain player in a From b2cfed93da267360535081dfe0b44731eef3afe6 Mon Sep 17 00:00:00 2001 From: zsawyer Date: Tue, 24 Jan 2023 22:41:15 +0100 Subject: [PATCH 2/3] add dimensionalHeight config parameter --- .../java/zsawyer/mods/mumblelink/Config.java | 10 +++++++++- .../mods/mumblelink/MumbleLinkImpl.java | 7 ++++++- .../mods/mumblelink/util/ConfigHelper.java | 18 ++++++++++++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/mod/src/main/java/zsawyer/mods/mumblelink/Config.java b/mod/src/main/java/zsawyer/mods/mumblelink/Config.java index f1c6daa..a7b317e 100644 --- a/mod/src/main/java/zsawyer/mods/mumblelink/Config.java +++ b/mod/src/main/java/zsawyer/mods/mumblelink/Config.java @@ -47,8 +47,15 @@ public class Config { public static final String ENABLED_PATH = "enabled"; public static final boolean ENABLED_DEFAULT_VALUE = true; + public static final String DIMENSIONAL_HEIGHT_COMMENT = "set the maximum expected height of dimensions"; + public static final String DIMENSIONAL_HEIGHT_TRANSLATION = MumbleLink.MOD_ID + ".configgui.dimensionalHeight"; + public static final String DIMENSIONAL_HEIGHT_PATH = "dimensionalHeight"; + public static final int DIMENSIONAL_HEIGHT_DEFAULT_VALUE = 512; + + public final ForgeConfigSpec.BooleanValue debug; public final ForgeConfigSpec.BooleanValue enabled; + public final ForgeConfigSpec.IntValue dimensionalHeight; static { final Pair specPair = new ForgeConfigSpec.Builder().configure(Config::new); @@ -63,6 +70,7 @@ public class Config { debug = ConfigHelper.buildBoolean(builder, DEBUG_PATH, DEBUG_COMMENT, DEBUG_TRANSLATION, DEBUG_DEFAULT_VALUE); enabled = ConfigHelper.buildBoolean(builder, ENABLED_PATH, ENABLED_COMMENT, ENABLED_TRANSLATION, ENABLED_DEFAULT_VALUE); + dimensionalHeight = ConfigHelper.buildInt(builder, DIMENSIONAL_HEIGHT_PATH, DIMENSIONAL_HEIGHT_COMMENT, DIMENSIONAL_HEIGHT_TRANSLATION, DIMENSIONAL_HEIGHT_DEFAULT_VALUE); builder.pop(); } @@ -73,6 +81,6 @@ public class Config { * @author zsawyer */ public enum Path { - enabled, debug; + enabled, debug, dimensionalHeight; } } diff --git a/mod/src/main/java/zsawyer/mods/mumblelink/MumbleLinkImpl.java b/mod/src/main/java/zsawyer/mods/mumblelink/MumbleLinkImpl.java index 0740dc0..610060f 100644 --- a/mod/src/main/java/zsawyer/mods/mumblelink/MumbleLinkImpl.java +++ b/mod/src/main/java/zsawyer/mods/mumblelink/MumbleLinkImpl.java @@ -24,7 +24,6 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.IExtensionPoint; @@ -66,6 +65,7 @@ public MumbleLinkImpl() { private boolean enabled = true; private boolean debug = false; + private int dimensionalHeight = 512; private String name = "MumbleLink"; private String version = "unknown"; @@ -97,6 +97,7 @@ private void loadConfig() { ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, Config.SPEC); // TODO: make this actually read from config debug = false;//Config.CONFIG.debug.get(); + dimensionalHeight = 512;//Config.CONFIG.enabled.get(); enabled = true;//Config.CONFIG.enabled.get(); } @@ -147,4 +148,8 @@ public String getName() { public String getVersion() { return version; } + + public static int dimensionalHeight() { + return instance.dimensionalHeight; + } } diff --git a/mod/src/main/java/zsawyer/mods/mumblelink/util/ConfigHelper.java b/mod/src/main/java/zsawyer/mods/mumblelink/util/ConfigHelper.java index f5c6d3c..7a60b53 100644 --- a/mod/src/main/java/zsawyer/mods/mumblelink/util/ConfigHelper.java +++ b/mod/src/main/java/zsawyer/mods/mumblelink/util/ConfigHelper.java @@ -65,4 +65,22 @@ public static ForgeConfigSpec.BooleanValue buildBoolean(ForgeConfigSpec.Builder .translation(translation) .define(path, defaultValue); } + + /** + * Short-hand function to get a {@link net.minecraftforge.common.ForgeConfigSpec.IntValue}, providing a comment, translation and + * default value. The comment will be supplemented with the range (1 to {@link Integer#MAX_VALUE}) + * + * @param builder a builder instance to work with + * @param path an identifier for this key-value pair + * @param comment a hint which will be written into the config file + * @param translation the key for the translation string + * @param defaultValue a default value to use if it wasn't set yet + * @return the value read from config + */ + public static ForgeConfigSpec.IntValue buildInt(ForgeConfigSpec.Builder builder, String path, String comment, String translation, int defaultValue) { + return builder + .comment(comment + System.getProperty("line.separator") + 1 + "-" + Integer.MAX_VALUE) + .translation(translation) + .defineInRange(path, defaultValue, 1, Integer.MAX_VALUE); + } } From 82114ce5f027ba426aaec523d3f49e587caf678c Mon Sep 17 00:00:00 2001 From: zsawyer Date: Tue, 24 Jan 2023 22:52:30 +0100 Subject: [PATCH 3/3] apply dimensional height offset similar to the fabric mod // Make people in other dimensions far away so that they're muted. val yAxisAdjuster = (world.registryKey.value.stableHash % 2048) * config.clientDimensionYAxisAdjust camPos[1] += yAxisAdjuster /** * A stable hash function designed for world IDs. * Different clients should be able to run this on the same world ID and get the same result. * * Based on the `djb2` hash function: [Hash Functions](http://www.cse.yorku.ca/~oz/hash.html) */ val Identifier.stableHash: Int get() { var hash = 5381 for (c in this.toString()) { hash += (hash shl 5) + c.code } return hash } fixes #35 --- .../mods/mumblelink/mumble/UpdateData.java | 29 +++++++++++++++++++ .../mumblelink/mumble/jna/LinkAPIHelper.java | 23 +++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/mod/src/main/java/zsawyer/mods/mumblelink/mumble/UpdateData.java b/mod/src/main/java/zsawyer/mods/mumblelink/mumble/UpdateData.java index d5c422b..0d1f3cb 100644 --- a/mod/src/main/java/zsawyer/mods/mumblelink/mumble/UpdateData.java +++ b/mod/src/main/java/zsawyer/mods/mumblelink/mumble/UpdateData.java @@ -22,6 +22,8 @@ package zsawyer.mods.mumblelink.mumble; import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import zsawyer.mods.mumblelink.MumbleLinkImpl; import zsawyer.mods.mumblelink.api.IdentityManipulator; @@ -36,6 +38,8 @@ * @author zsawyer */ public class UpdateData { + private static final int HEIGHT_INDEX = 1; + float[] fAvatarPosition = {0, 0, 0}; // [3] float[] fAvatarFront = {0, 0, 0}; // [3] @@ -135,6 +139,7 @@ public void set(Minecraft game) { (float) game.player.getPosition(1f).y() * fAvatarPositionY, (float) game.player.getPosition(1f).z() * fAvatarPositionZ }; + applyDimensionalOffset(game, fAvatarPosition); // Unit vector pointing out of the avatar's eyes (here Front looks // into scene). @@ -159,6 +164,7 @@ public void set(Minecraft game) { (float) game.player.getPosition(1f).y() * fCameraPositionY, (float) game.player.getPosition(1f).z() * fCameraPositionZ }; + applyDimensionalOffset(game, fCameraPosition); fCameraFront = new float[]{ (float) lookDirection.x * fCameraFrontX, @@ -211,4 +217,27 @@ protected String generateContext(Minecraft game, int maxLength) { private Vec3 getTopVec(Minecraft game) { return game.player.getUpVector(1f); } + + + /** + * Make people in other dimensions far away so that they're muted. + *

+ * reimplementation of https://github.com/magneticflux-/fabric-mumblelink-mod/blob/12727324ae9ecfc9c6b0ab5b604e824d43cfffa1/src/main/kotlin/com/skaggsm/mumblelinkmod/client/ClientMumbleLinkMod.kt#L136 + * + * @param game the source to get live data from + * @param originalPosition the original position to be offset + */ + public static void applyDimensionalOffset(Minecraft game, float[] originalPosition) { + ResourceKey dimension = game.player.level.dimension(); + if (dimension == null) { + // silently ignoring because it would become too spammy + return; + } + + int configuredOffset = MumbleLinkImpl.dimensionalHeight(); + int hash = LinkAPIHelper.stableHash(dimension.toString()); + float heightOffset = (hash % 2048) * configuredOffset; + + originalPosition[HEIGHT_INDEX] += heightOffset; + } } diff --git a/mod/src/main/java/zsawyer/mods/mumblelink/mumble/jna/LinkAPIHelper.java b/mod/src/main/java/zsawyer/mods/mumblelink/mumble/jna/LinkAPIHelper.java index 716e976..7162653 100644 --- a/mod/src/main/java/zsawyer/mods/mumblelink/mumble/jna/LinkAPIHelper.java +++ b/mod/src/main/java/zsawyer/mods/mumblelink/mumble/jna/LinkAPIHelper.java @@ -27,6 +27,7 @@ import java.nio.ByteBuffer; import java.nio.CharBuffer; +import java.util.PrimitiveIterator; /** * @author zsawyer @@ -54,6 +55,28 @@ public static ByteBuffer parseToByteBuffer(int capacity, String value) { return buffer; } + /** + * A stable hash function designed for world IDs. + * Different clients should be able to run this on the same world ID and get the same result. + *

+ * Based on the `djb2` hash function: [Hash Functions](http://www.cse.yorku.ca/~oz/hash.html) + *

+ * reimplementation of https://github.com/magneticflux-/fabric-mumblelink-mod/blob/3866317c64f9b7f5b9b4f17e88cd51c0a717b993/src/main/kotlin/com/skaggsm/mumblelinkmod/client/Utils.kt#L21 + * + * @param hashingTarget the strings whose character sequence should be hashed + * @return the stable hash built for the given input + */ + public static int stableHash(String hashingTarget) { + int hash = 5381; + PrimitiveIterator.OfInt characterIterator = hashingTarget.chars().iterator(); + + while (characterIterator.hasNext()) { + hash += (hash << 5) + characterIterator.nextInt(); + } + + return hash; + } + public synchronized LinkAPILibrary getLibraryInstance() { return libraryInstance; }