Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Dimensional Height Offset #35

Open
wants to merge 2 commits into
base: releases/1.18.1
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion mod/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'idea'
apply plugin: 'maven-publish'

ext.modversion = "4.4.1"
ext.modversion = "4.5.0"
zsawyer marked this conversation as resolved.
Show resolved Hide resolved
ext.mcversion = "1.15.2"
ext.forgeversion = "31.1.0"

Expand Down
89 changes: 89 additions & 0 deletions mod/src/main/java/zsawyer/mods/mumblelink/mumble/UpdateData.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ public class UpdateData {
NativeUpdateErrorHandler errorHandler;
private int uiTick = 0;

private int dimensionYOffset = 0;
private int dimensionOffsetUpdateCounter = 0;

// First prime number higher than (2^16 + 512) / 13
final int DIMENSION_OFFSET_SEED = 5081;
final int DIMENSION_OFFSET_UPDATE_RATE = 101;

public UpdateData(LinkAPILibrary mumbleLink,
NativeUpdateErrorHandler errorHandler) {
this.mumbleLink = mumbleLink;
Expand Down Expand Up @@ -177,6 +184,8 @@ public void set(Minecraft game) {
Float.parseFloat(Double.toString(topDirection.y
* fCameraTopY))};

handleDimensionYOffset(game);

// Identifier which uniquely identifies a certain player in a
// context (e.g. the ingame Name).
identity = generateIdentity(game,
Expand Down Expand Up @@ -233,4 +242,84 @@ private Vec3d getTopVec(Minecraft game) {

return new Vec3d((double) (f2 * f3), (double) f4, (double) (f1 * f3));
}

private void handleDimensionYOffset(Minecraft game) {
// Don't recalculate this every time, optimally this only needs to be done when a server/world is joined or when
// the player enters a different dimension.
if (dimensionOffsetUpdateCounter <= 0) {
// Todo: Call this as well or only on dimension change
zsawyer marked this conversation as resolved.
Show resolved Hide resolved
calculateDimensionYOffset(game);
dimensionOffsetUpdateCounter = DIMENSION_OFFSET_UPDATE_RATE;
}

dimensionOffsetUpdateCounter--;

if (dimensionYOffset != 0) {
zsawyer marked this conversation as resolved.
Show resolved Hide resolved
// Offset the Y-coordinate based on the dimension
fAvatarPosition[2] += dimensionYOffset;
fCameraPosition[2] += dimensionYOffset;
}
}

private void calculateDimensionYOffset(Minecraft game) {
/*
* Since the Link API coordinates are stored in floats, and those only have 23 bits of precision, at coordinates
* around 2^16 meters, the positional audio precision is already reduced to centimeters and becomes increasingly
* after that. At 2^23 a float can not contain more precise location data than meters. This is why a maximum
* y-offset around 2^16 (65536) was chosen.
* Now there is no way to fit a 256 y-range for each possible dimension id in the range of -65536 to 65536, so
* instead the three vanilla dimensions, Nether, Overworld and End get their own reserved "Mumble-space" of 256
* meters high and the rest of the dimensions are distributed over the space in between with the realistic chance
* of overlapping positional audio spaces, but it is what it is...
*
* The distribution is as follows:
*
* |---------------|----------------------|------------|----------------------|----------|
* -(2^16) -(2^16)+256 0 256 2^16 2^16+256
* Nether Negative ID Mod dims Overworld Positive ID Mod dims End
*/

// Coordinates are stored in a float array, which starts to lose precision in the magnitude of meters at 2^23.
// To be useful for positional audio use 2^16 (65536) as a maximum offset to only lose precision in the magnitude of centimeters.
int maxYOffset = 65536;

if (game.world == null) {
// If we don't know what to do, just use the maximum non-vanilla dimension offset so the "Mumble space"
// won't overlap with the Overworld or End.
dimensionYOffset = maxYOffset - 256;
return;
}

int dimID = game.world.dimension.getType().getId();

switch (dimID) {
case 0:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there maybe an enum that we can use here?
Like
Dimension.overworld.getId()

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In MC 1.16 there is an enum that can be used, but this pull request is for MC 1.15

In MC 1.15 there are functions Dimension.isNether and Dimension.isSurfaceWorld however the ID would still be needed to identify the End.
So it is better to leave it this way in my honest opinion.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, Now I get it. Please use named constants though -> DIM_ID_NETHER, DIM_ID_END, DIM_ID_OVERWORLD
(maybe even remove the comments because it becomes self-explanatory)

// Overworld
dimensionYOffset = 0;
return;
case -1:
// Nether
dimensionYOffset = -1 * maxYOffset;
return;
case 1:
// End
dimensionYOffset = maxYOffset;
return;
default:
// In all other cases, use the distribution function.
break;
}

// Min_INT * Min_ INT < Max_LONG
// -(2^31) * -(2^31) = 2^62 < 2^63-1
long rawYOffset = Math.abs((long) DIMENSION_OFFSET_SEED * (long) dimID);

// Transform the offset to be distributed between 256 and 2^16 - 256
dimensionYOffset = (int) (rawYOffset % (maxYOffset - 512) + 256);
zsawyer marked this conversation as resolved.
Show resolved Hide resolved
zsawyer marked this conversation as resolved.
Show resolved Hide resolved

// Transform the offset to be distributed between -(2^16) + 256 and -256
if (dimID < 0) {
dimensionYOffset *= -1;
}
}
}