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

feat: make above-bedrock-nether-building option a player preference #3685

Closed
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
1 change: 0 additions & 1 deletion core/src/main/java/org/geysermc/geyser/GeyserImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,6 @@ private void startInstance() {
}

CooldownUtils.setDefaultShowCooldown(config.getShowCooldown());
DimensionUtils.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether

// https://github.com/GeyserMC/Geyser/issues/957
RakNetConstants.MAXIMUM_MTU_SIZE = (short) config.getMtu();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ protected AttributeData calculateAttribute(Attribute javaAttribute, GeyserAttrib
public void setLastDeathPosition(@Nullable GlobalPos pos) {
if (pos != null) {
dirtyMetadata.put(EntityData.PLAYER_LAST_DEATH_POS, pos.getPosition());
dirtyMetadata.put(EntityData.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension()));
dirtyMetadata.put(EntityData.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(session, pos.getDimension()));
dirtyMetadata.put(EntityData.PLAYER_HAS_DIED, (byte) 1);
} else {
dirtyMetadata.put(EntityData.PLAYER_HAS_DIED, (byte) 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1486,7 +1486,7 @@ private void startGame() {
startGamePacket.setRotation(Vector2f.from(1, 1));

startGamePacket.setSeed(-1L);
startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(chunkCache.getBedrockDimension()));
startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(this, chunkCache.getBedrockDimension()));
startGamePacket.setGeneratorId(1);
startGamePacket.setLevelGameType(GameType.SURVIVAL);
startGamePacket.setDifficulty(1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ public class PreferencesCache {
@Setter
private boolean prefersCustomSkulls;

/**
* If the session wants to enable above bedrock Nether building.
*/
@Setter
private boolean prefersAboveBedrockNetherBuilding;

/**
* Which CooldownType the client prefers. Initially set to {@link CooldownUtils#getDefaultShowCooldown()}.
*/
Expand Down Expand Up @@ -84,4 +90,11 @@ public void updateShowCoordinates() {
public boolean showCustomSkulls() {
return prefersCustomSkulls && session.getGeyser().getConfig().isAllowCustomSkulls();
}

/**
* @return true if the session prefers above bedrock Nether building, and the config allows them.
*/
public boolean allowAboveBedrockNetherBuilding() {
return prefersAboveBedrockNetherBuilding && session.getGeyser().getConfig().isAboveBedrockNetherBuilding();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public void translate(GeyserSession session, PositionTrackingDBClientRequestPack

// Build the NBT data for the update
NbtMapBuilder builder = NbtMap.builder();
builder.putInt("dim", DimensionUtils.javaToBedrock(pos.dimension()));
builder.putInt("dim", DimensionUtils.javaToBedrock(session, pos.dimension()));
builder.putString("id", "0x" + String.format("%08X", packet.getTrackingId()));

builder.putByte("version", (byte) 1); // Not sure what this is for
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public void translate(GeyserSession session, ClientboundLoginPacket packet) {
// If the player is already initialized and a join game packet is sent, they
// are swapping servers
if (session.isSpawned()) {
String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), packet.getDimension());
String fakeDim = DimensionUtils.getTemporaryDimension(session, session.getDimension(), packet.getDimension());
DimensionUtils.switchDimension(session, fakeDim);

session.getWorldCache().removeScoreboard();
Expand Down Expand Up @@ -146,7 +146,7 @@ public void translate(GeyserSession session, ClientboundLoginPacket packet) {

if (!newDimension.equals(session.getDimension())) {
DimensionUtils.switchDimension(session, newDimension);
} else if (DimensionUtils.isCustomBedrockNetherId() && newDimension.equalsIgnoreCase(DimensionUtils.NETHER)) {
} else if (session.getPreferencesCache().allowAboveBedrockNetherBuilding() && newDimension.equalsIgnoreCase(DimensionUtils.NETHER)) {
// If the player is spawning into the "fake" nether, send them some fog
session.sendFog("minecraft:fog_hell");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ public void translate(GeyserSession session, ClientboundRespawnPacket packet) {
String newDimension = packet.getDimension();
if (!session.getDimension().equals(newDimension) || !packet.getWorldName().equals(session.getWorldName())) {
// Switching to a new world (based off the world name change or new dimension); send a fake dimension change
if (DimensionUtils.javaToBedrock(session.getDimension()) == DimensionUtils.javaToBedrock(newDimension)) {
String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), newDimension);
if (DimensionUtils.javaToBedrock(session, session.getDimension()) == DimensionUtils.javaToBedrock(session, newDimension)) {
String fakeDim = DimensionUtils.getTemporaryDimension(session, session.getDimension(), newDimension);
DimensionUtils.switchDimension(session, fakeDim);
}
session.setWorldName(packet.getWorldName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public void translate(GeyserSession session, ClientboundAnimatePacket packet) {
// Spawn custom particle
SpawnParticleEffectPacket stringPacket = new SpawnParticleEffectPacket();
stringPacket.setIdentifier("geyseropt:enchanted_hit_multiple");
stringPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getDimension()));
stringPacket.setDimensionId(DimensionUtils.javaToBedrock(session, session.getDimension()));
stringPacket.setPosition(Vector3f.ZERO);
stringPacket.setUniqueEntityId(entity.getGeyserId());
stringPacket.setMolangVariablesJson(Optional.empty());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ private Function<Vector3f, BedrockPacket> createParticle(GeyserSession session,
return packet;
};
} else if (particleMapping.identifier() != null) {
int dimensionId = DimensionUtils.javaToBedrock(session.getDimension());
int dimensionId = DimensionUtils.javaToBedrock(session, session.getDimension());
return (position) -> {
SpawnParticleEffectPacket stringPacket = new SpawnParticleEffectPacket();
stringPacket.setIdentifier(particleMapping.identifier());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void translate(GeyserSession session, ClientboundMapItemDataPacket packet
boolean shouldStore = false;

mapItemDataPacket.setUniqueMapId(packet.getMapId());
mapItemDataPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getDimension()));
mapItemDataPacket.setDimensionId(DimensionUtils.javaToBedrock(session, session.getDimension()));
mapItemDataPacket.setLocked(packet.isLocked());
mapItemDataPacket.setOrigin(Vector3i.ZERO); // Required since 1.19.20
mapItemDataPacket.setScale(packet.getScale());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public class JavaSetDefaultSpawnPositionTranslator extends PacketTranslator<Clie
public void translate(GeyserSession session, ClientboundSetDefaultSpawnPositionPacket packet) {
SetSpawnPositionPacket spawnPositionPacket = new SetSpawnPositionPacket();
spawnPositionPacket.setBlockPosition(packet.getPosition());
spawnPositionPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getDimension()));
spawnPositionPacket.setDimensionId(DimensionUtils.javaToBedrock(session, session.getDimension()));
spawnPositionPacket.setSpawnType(SetSpawnPositionPacket.Type.WORLD_SPAWN);
session.sendUpstreamPacket(spawnPositionPacket);
}
Expand Down
85 changes: 47 additions & 38 deletions core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,30 @@
import java.util.Set;

public class DimensionUtils {

// Changes if the above-bedrock Nether building workaround is applied
private static int BEDROCK_NETHER_ID = 1;

/**
* String reference to vanilla Java overworld dimension identifier
*/
public static final String OVERWORLD = "minecraft:overworld";

/**
* String reference to vanilla Java nether dimension identifier
*/
public static final String NETHER = "minecraft:the_nether";

/**
* String reference to vanilla Java end dimension identifier
*/
public static final String THE_END = "minecraft:the_end";

/**
* Switches the dimension (Java identifier) for a given Geyser session.
*
* @param session Geyser session
* @param javaDimension Minecraft Java edition dimension identifier
*/
public static void switchDimension(GeyserSession session, String javaDimension) {
int bedrockDimension = javaToBedrock(javaDimension);
int previousDimension = javaToBedrock(session.getDimension());
int bedrockDimension = javaToBedrock(session, javaDimension);
int previousDimension = javaToBedrock(session, session.getDimension());

Entity player = session.getPlayerEntity();

Expand Down Expand Up @@ -142,77 +146,82 @@ public static void switchDimension(GeyserSession session, String javaDimension)
// If the bedrock nether height workaround is enabled, meaning the client is told it's in the end dimension,
// we check if the player is entering the nether and apply the nether fog to fake the fact that the client
// thinks they are in the end dimension.
if (BEDROCK_NETHER_ID == 2) {
if (session.getPreferencesCache().allowAboveBedrockNetherBuilding()) {
if (NETHER.equals(javaDimension)) {
session.sendFog("minecraft:fog_hell");
} else if (previousDimension == BEDROCK_NETHER_ID) {
} else if (previousDimension == 2) {
session.removeFog("minecraft:fog_hell");
}
}
}

/**
* Sets the Bedrock dimension in the chunk cache for a given Minecraft dimension identifier (Java).
*
* @param session Geyser session (this is used to check whether the "fake" Nether is enabled)
* @param javaDimension Minecraft Java edition dimension identifier
*/
public static void setBedrockDimension(GeyserSession session, String javaDimension) {
session.getChunkCache().setBedrockDimension(switch (javaDimension) {
case DimensionUtils.THE_END -> BedrockDimension.THE_END;
case DimensionUtils.NETHER -> DimensionUtils.isCustomBedrockNetherId() ? BedrockDimension.THE_END : BedrockDimension.THE_NETHER;
case DimensionUtils.NETHER -> session.getPreferencesCache().allowAboveBedrockNetherBuilding() ? BedrockDimension.THE_END : BedrockDimension.THE_NETHER;
default -> BedrockDimension.OVERWORLD;
});
}

public static int javaToBedrock(BedrockDimension dimension) {
if (dimension == BedrockDimension.THE_NETHER) {
return BEDROCK_NETHER_ID;
} else if (dimension == BedrockDimension.THE_END) {
return 2;
} else {
return 0;
}
/**
* Maps a Minecraft Java edition dimension to a Bedrock dimension identifier.
*
* @param session Geyser session (this is used to check whether the "fake" Nether is enabled)
* @param dimension Minecraft Bedrock edition dimension
* @return Minecraft Bedrock edition dimension identifier
*/
public static int javaToBedrock(GeyserSession session, BedrockDimension dimension) {
return switch (dimension) {
case BedrockDimension.THE_NETHER -> session.getPreferencesCache().allowAboveBedrockNetherBuilding() ? 2 : 1;
case BedrockDimension.THE_END -> 2;
default -> 0;
};
}

/**
* Map the Java edition dimension IDs to Bedrock edition
* Maps a Minecraft Java edition dimension to a Bedrock dimension identifier.
*
* @param javaDimension Dimension ID to convert
* @return Converted Bedrock edition dimension ID
* @param javaDimension Minecraft Java edition dimension identifier
* @return Minecraft Bedrock edition dimension identifier
*/
public static int javaToBedrock(String javaDimension) {
return switch (javaDimension) {
case NETHER -> BEDROCK_NETHER_ID;
case NETHER -> 1;
case THE_END -> 2;
default -> 0;
};
}

/**
* The Nether dimension in Bedrock does not permit building above Y128 - the Bedrock above the dimension.
* This workaround sets the Nether as the End dimension to ignore this limit.
*
* @param isAboveNetherBedrockBuilding true if we should apply The End workaround
*/
public static void changeBedrockNetherId(boolean isAboveNetherBedrockBuilding) {
// Change dimension ID to the End to allow for building above Bedrock
BEDROCK_NETHER_ID = isAboveNetherBedrockBuilding ? 2 : 1;
public static int javaToBedrock(GeyserSession session, String javaDimension) {
return switch (javaDimension) {
case NETHER -> session.getPreferencesCache().allowAboveBedrockNetherBuilding() ? 2 : 1;
case THE_END -> 2;
default -> 0;
};
}

/**
* Gets the fake, temporary dimension we send clients to so we aren't switching to the same dimension without an additional
* dimension switch.
*
* @param session Geyser session (this is used to check whether the "fake" Nether is enabled)
* @param currentDimension the current dimension of the player
* @param newDimension the new dimension that the player will be transferred to
* @return the fake dimension to transfer to
*/
public static String getTemporaryDimension(String currentDimension, String newDimension) {
if (BEDROCK_NETHER_ID == 2) {
public static String getTemporaryDimension(GeyserSession session, String currentDimension, String newDimension) {
if (session.getPreferencesCache().allowAboveBedrockNetherBuilding()) {
// Prevents rare instances of Bedrock locking up
return javaToBedrock(newDimension) == 2 ? OVERWORLD : NETHER;
return javaToBedrock(session, newDimension) == 2 ? OVERWORLD : NETHER;
}
// Check current Bedrock dimension and not just the Java dimension.
// Fixes rare instances like https://github.com/GeyserMC/Geyser/issues/3161
return javaToBedrock(currentDimension) == 0 ? NETHER : OVERWORLD;
}

public static boolean isCustomBedrockNetherId() {
return BEDROCK_NETHER_ID == 2;
return javaToBedrock(session, currentDimension) == 0 ? NETHER : OVERWORLD;
}
}
11 changes: 10 additions & 1 deletion core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ public static CustomForm buildForm(GeyserSession session) {
// Only show the client title if any of the client settings are available
boolean showClientSettings = session.getPreferencesCache().isAllowShowCoordinates()
|| CooldownUtils.getDefaultShowCooldown() != CooldownUtils.CooldownType.DISABLED
|| session.getGeyser().getConfig().isAllowCustomSkulls();
|| session.getGeyser().getConfig().isAllowCustomSkulls()
|| session.getGeyser().getConfig().isAboveBedrockNetherBuilding();

if (showClientSettings) {
builder.label("geyser.settings.title.client");
Expand All @@ -75,6 +76,10 @@ public static CustomForm buildForm(GeyserSession session) {
if (session.getGeyser().getConfig().isAllowCustomSkulls()) {
builder.toggle("geyser.settings.option.customSkulls", session.getPreferencesCache().isPrefersCustomSkulls());
}

if (session.getGeyser().getConfig().isAboveBedrockNetherBuilding()) {
builder.toggle("geyser.settings.option.aboveBedrockNetherBuilding", session.getPreferencesCache().isPrefersAboveBedrockNetherBuilding());
axieum marked this conversation as resolved.
Show resolved Hide resolved
}
}

boolean canModifyServer = session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server");
Expand Down Expand Up @@ -126,6 +131,10 @@ public static CustomForm buildForm(GeyserSession session) {
if (session.getGeyser().getConfig().isAllowCustomSkulls()) {
session.getPreferencesCache().setPrefersCustomSkulls(response.next());
}

if (session.getGeyser().getConfig().isAboveBedrockNetherBuilding()) {
session.getPreferencesCache().setPrefersAboveBedrockNetherBuilding(response.next());
}
}

if (canModifyServer) {
Expand Down