mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Fix some server switching issues and GeyserConnect
This commit is contained in:
parent
95c6f7c9cf
commit
3d7e62a408
10 changed files with 37 additions and 36 deletions
|
@ -321,7 +321,7 @@ public class SessionPlayerEntity extends PlayerEntity {
|
||||||
|
|
||||||
public int voidFloorPosition() {
|
public int voidFloorPosition() {
|
||||||
// The void floor is offset about 40 blocks below the bottom of the world
|
// The void floor is offset about 40 blocks below the bottom of the world
|
||||||
BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension();
|
BedrockDimension bedrockDimension = session.getBedrockDimension();
|
||||||
return bedrockDimension.minY() - 40;
|
return bedrockDimension.minY() - 40;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,9 @@ import org.geysermc.geyser.util.DimensionUtils;
|
||||||
* Represents the information we store from the current Java dimension
|
* Represents the information we store from the current Java dimension
|
||||||
* @param piglinSafe Whether piglins and hoglins are safe from conversion in this dimension.
|
* @param piglinSafe Whether piglins and hoglins are safe from conversion in this dimension.
|
||||||
* This controls if they have the shaking effect applied in the dimension.
|
* This controls if they have the shaking effect applied in the dimension.
|
||||||
|
* @param bedrockId the Bedrock dimension ID of this dimension.
|
||||||
|
* As a Java dimension can be null in some login cases (e.g. GeyserConnect), make sure the player
|
||||||
|
* is logged in before utilizing this field.
|
||||||
*/
|
*/
|
||||||
public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale, int bedrockId, boolean isNetherLike) {
|
public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale, int bedrockId, boolean isNetherLike) {
|
||||||
|
|
||||||
|
@ -46,7 +49,7 @@ public record JavaDimension(int minY, int maxY, boolean piglinSafe, double world
|
||||||
// Set if piglins/hoglins should shake
|
// Set if piglins/hoglins should shake
|
||||||
boolean piglinSafe = dimension.getBoolean("piglin_safe");
|
boolean piglinSafe = dimension.getBoolean("piglin_safe");
|
||||||
// Load world coordinate scale for the world border
|
// Load world coordinate scale for the world border
|
||||||
double coordinateScale = dimension.getDouble("coordinate_scale");
|
double coordinateScale = dimension.getNumber("coordinate_scale").doubleValue(); // FIXME see if we can change this in the NBT library itself.
|
||||||
|
|
||||||
boolean isNetherLike;
|
boolean isNetherLike;
|
||||||
// Cache the Bedrock version of this dimension, and base it off the ID - THE ID CAN CHANGE!!!
|
// Cache the Bedrock version of this dimension, and base it off the ID - THE ID CAN CHANGE!!!
|
||||||
|
|
|
@ -137,6 +137,7 @@ import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
||||||
import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
|
import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData;
|
||||||
import org.geysermc.geyser.item.Items;
|
import org.geysermc.geyser.item.Items;
|
||||||
import org.geysermc.geyser.item.type.BlockItem;
|
import org.geysermc.geyser.item.type.BlockItem;
|
||||||
|
import org.geysermc.geyser.level.BedrockDimension;
|
||||||
import org.geysermc.geyser.level.JavaDimension;
|
import org.geysermc.geyser.level.JavaDimension;
|
||||||
import org.geysermc.geyser.level.physics.CollisionManager;
|
import org.geysermc.geyser.level.physics.CollisionManager;
|
||||||
import org.geysermc.geyser.network.netty.LocalSession;
|
import org.geysermc.geyser.network.netty.LocalSession;
|
||||||
|
@ -386,6 +387,13 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||||
@MonotonicNonNull
|
@MonotonicNonNull
|
||||||
@Setter
|
@Setter
|
||||||
private JavaDimension dimensionType = null;
|
private JavaDimension dimensionType = null;
|
||||||
|
/**
|
||||||
|
* Which dimension Bedrock understands themselves to be in.
|
||||||
|
* This should only be set after the ChangeDimensionPacket is sent, or
|
||||||
|
* right before the StartGamePacket is sent.
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
private BedrockDimension bedrockDimension = BedrockDimension.OVERWORLD;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private int breakingBlock;
|
private int breakingBlock;
|
||||||
|
@ -1547,7 +1555,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||||
startGamePacket.setRotation(Vector2f.from(1, 1));
|
startGamePacket.setRotation(Vector2f.from(1, 1));
|
||||||
|
|
||||||
startGamePacket.setSeed(-1L);
|
startGamePacket.setSeed(-1L);
|
||||||
startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(chunkCache.getBedrockDimension()));
|
startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(bedrockDimension));
|
||||||
startGamePacket.setGeneratorId(1);
|
startGamePacket.setGeneratorId(1);
|
||||||
startGamePacket.setLevelGameType(GameType.SURVIVAL);
|
startGamePacket.setLevelGameType(GameType.SURVIVAL);
|
||||||
startGamePacket.setDifficulty(1);
|
startGamePacket.setDifficulty(1);
|
||||||
|
|
|
@ -25,17 +25,14 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.session.cache;
|
package org.geysermc.geyser.session.cache;
|
||||||
|
|
||||||
import org.geysermc.geyser.level.block.type.Block;
|
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette;
|
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.geysermc.geyser.level.BedrockDimension;
|
import org.geysermc.geyser.level.block.type.Block;
|
||||||
import org.geysermc.geyser.level.block.BlockStateValues;
|
|
||||||
import org.geysermc.geyser.level.chunk.GeyserChunk;
|
import org.geysermc.geyser.level.chunk.GeyserChunk;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
import org.geysermc.geyser.util.MathUtils;
|
import org.geysermc.geyser.util.MathUtils;
|
||||||
|
import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette;
|
||||||
|
|
||||||
public class ChunkCache {
|
public class ChunkCache {
|
||||||
private final boolean cache;
|
private final boolean cache;
|
||||||
|
@ -46,13 +43,6 @@ public class ChunkCache {
|
||||||
@Setter
|
@Setter
|
||||||
private int heightY;
|
private int heightY;
|
||||||
|
|
||||||
/**
|
|
||||||
* Which dimension Bedrock understands themselves to be in.
|
|
||||||
*/
|
|
||||||
@Getter
|
|
||||||
@Setter
|
|
||||||
private BedrockDimension bedrockDimension = BedrockDimension.OVERWORLD;
|
|
||||||
|
|
||||||
public ChunkCache(GeyserSession session) {
|
public ChunkCache(GeyserSession session) {
|
||||||
this.cache = !session.getGeyser().getWorldManager().hasOwnChunkCache(); // To prevent Spigot from initializing
|
this.cache = !session.getGeyser().getWorldManager().hasOwnChunkCache(); // To prevent Spigot from initializing
|
||||||
chunks = cache ? new Long2ObjectOpenHashMap<>() : null;
|
chunks = cache ? new Long2ObjectOpenHashMap<>() : null;
|
||||||
|
|
|
@ -64,14 +64,17 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
|
||||||
|
|
||||||
PlayerSpawnInfo spawnInfo = packet.getCommonPlayerSpawnInfo();
|
PlayerSpawnInfo spawnInfo = packet.getCommonPlayerSpawnInfo();
|
||||||
JavaDimension newDimension = session.getRegistryCache().dimensions().byId(spawnInfo.getDimension());
|
JavaDimension newDimension = session.getRegistryCache().dimensions().byId(spawnInfo.getDimension());
|
||||||
boolean forceDimSwitch = false;
|
|
||||||
|
|
||||||
// If the player is already initialized and a join game packet is sent, they
|
// If the player is already initialized and a join game packet is sent, they
|
||||||
// are swapping servers
|
// are swapping servers
|
||||||
if (session.isSpawned()) {
|
if (session.isSpawned()) {
|
||||||
int fakeDim = DimensionUtils.getTemporaryDimension(session.getDimensionType().bedrockId(), newDimension.bedrockId());
|
int fakeDim = DimensionUtils.getTemporaryDimension(DimensionUtils.javaToBedrock(session.getBedrockDimension()), newDimension.bedrockId());
|
||||||
|
if (fakeDim != newDimension.bedrockId()) {
|
||||||
|
// The player's current dimension and new dimension are the same
|
||||||
|
// We want a dimension switch to clear old chunks out, so switch to a dimension that isn't the one we're currently in.
|
||||||
|
// Another dimension switch will be required to switch back
|
||||||
DimensionUtils.fastSwitchDimension(session, fakeDim);
|
DimensionUtils.fastSwitchDimension(session, fakeDim);
|
||||||
forceDimSwitch = true;
|
}
|
||||||
|
|
||||||
session.getWorldCache().removeScoreboard();
|
session.getWorldCache().removeScoreboard();
|
||||||
|
|
||||||
|
@ -80,15 +83,9 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
|
||||||
// Remove extra hearts, hunger, etc.
|
// Remove extra hearts, hunger, etc.
|
||||||
entity.resetAttributes();
|
entity.resetAttributes();
|
||||||
entity.resetMetadata();
|
entity.resetMetadata();
|
||||||
} else if (session.getUpstream().isInitialized()) {
|
|
||||||
if (newDimension.bedrockId() == 0) {
|
|
||||||
// A dimension switch will not happen, so make sure we initialized the dimension choice.
|
|
||||||
// Otherwise, the dimension switch will fill these values in.
|
|
||||||
session.setDimensionType(newDimension);
|
|
||||||
DimensionUtils.setBedrockDimension(session, newDimension.bedrockId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session.setDimensionType(newDimension);
|
||||||
session.setWorldName(spawnInfo.getWorldName());
|
session.setWorldName(spawnInfo.getWorldName());
|
||||||
session.setLevels(Arrays.stream(packet.getWorldNames()).map(Key::asString).toArray(String[]::new));
|
session.setLevels(Arrays.stream(packet.getWorldNames()).map(Key::asString).toArray(String[]::new));
|
||||||
session.setGameMode(spawnInfo.getGameMode());
|
session.setGameMode(spawnInfo.getGameMode());
|
||||||
|
@ -96,7 +93,6 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
|
||||||
boolean needsSpawnPacket = !session.isSentSpawnPacket();
|
boolean needsSpawnPacket = !session.isSentSpawnPacket();
|
||||||
if (needsSpawnPacket) {
|
if (needsSpawnPacket) {
|
||||||
// The player has yet to spawn so let's do that using some of the information in this Java packet
|
// The player has yet to spawn so let's do that using some of the information in this Java packet
|
||||||
session.setDimensionType(newDimension);
|
|
||||||
DimensionUtils.setBedrockDimension(session, newDimension.bedrockId());
|
DimensionUtils.setBedrockDimension(session, newDimension.bedrockId());
|
||||||
session.connect();
|
session.connect();
|
||||||
|
|
||||||
|
@ -131,7 +127,7 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
|
||||||
}
|
}
|
||||||
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(register, Constants.PLUGIN_MESSAGE.getBytes(StandardCharsets.UTF_8)));
|
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(register, Constants.PLUGIN_MESSAGE.getBytes(StandardCharsets.UTF_8)));
|
||||||
|
|
||||||
if (newDimension != session.getDimensionType() || forceDimSwitch) {
|
if (DimensionUtils.javaToBedrock(session.getBedrockDimension()) != newDimension.bedrockId()) {
|
||||||
DimensionUtils.switchDimension(session, newDimension);
|
DimensionUtils.switchDimension(session, newDimension);
|
||||||
} else if (DimensionUtils.isCustomBedrockNetherId() && newDimension.isNetherLike()) {
|
} else if (DimensionUtils.isCustomBedrockNetherId() && newDimension.isNetherLike()) {
|
||||||
// If the player is spawning into the "fake" nether, send them some fog
|
// If the player is spawning into the "fake" nether, send them some fog
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
package org.geysermc.geyser.translator.protocol.java.inventory;
|
package org.geysermc.geyser.translator.protocol.java.inventory;
|
||||||
|
|
||||||
|
import org.geysermc.geyser.entity.type.living.animal.horse.SkeletonHorseEntity;
|
||||||
|
import org.geysermc.geyser.entity.type.living.animal.horse.ZombieHorseEntity;
|
||||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundHorseScreenOpenPacket;
|
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundHorseScreenOpenPacket;
|
||||||
import org.cloudburstmc.nbt.NbtMap;
|
import org.cloudburstmc.nbt.NbtMap;
|
||||||
import org.cloudburstmc.nbt.NbtMapBuilder;
|
import org.cloudburstmc.nbt.NbtMapBuilder;
|
||||||
|
@ -140,8 +142,10 @@ public class JavaHorseScreenOpenTranslator extends PacketTranslator<ClientboundH
|
||||||
} else {
|
} else {
|
||||||
inventoryTranslator = new HorseInventoryTranslator(slotCount);
|
inventoryTranslator = new HorseInventoryTranslator(slotCount);
|
||||||
slots.add(SADDLE_SLOT);
|
slots.add(SADDLE_SLOT);
|
||||||
|
if (!(entity instanceof SkeletonHorseEntity || entity instanceof ZombieHorseEntity)) {
|
||||||
slots.add(ARMOR_SLOT);
|
slots.add(ARMOR_SLOT);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Build the NbtMap that sets the icons for Bedrock (e.g. sets the saddle outline on the saddle slot)
|
// Build the NbtMap that sets the icons for Bedrock (e.g. sets the saddle outline on the saddle slot)
|
||||||
builder.putList("slots", NbtType.COMPOUND, slots);
|
builder.putList("slots", NbtType.COMPOUND, slots);
|
||||||
|
|
|
@ -99,7 +99,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
||||||
BitSet waterloggedPaletteIds = new BitSet();
|
BitSet waterloggedPaletteIds = new BitSet();
|
||||||
BitSet bedrockOnlyBlockEntityIds = new BitSet();
|
BitSet bedrockOnlyBlockEntityIds = new BitSet();
|
||||||
|
|
||||||
BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension();
|
BedrockDimension bedrockDimension = session.getBedrockDimension();
|
||||||
int maxBedrockSectionY = (bedrockDimension.height() >> 4) - 1;
|
int maxBedrockSectionY = (bedrockDimension.height() >> 4) - 1;
|
||||||
|
|
||||||
int sectionCount;
|
int sectionCount;
|
||||||
|
@ -509,7 +509,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator<Clientbo
|
||||||
levelChunkPacket.setChunkX(packet.getX());
|
levelChunkPacket.setChunkX(packet.getX());
|
||||||
levelChunkPacket.setChunkZ(packet.getZ());
|
levelChunkPacket.setChunkZ(packet.getZ());
|
||||||
levelChunkPacket.setData(Unpooled.wrappedBuffer(payload));
|
levelChunkPacket.setData(Unpooled.wrappedBuffer(payload));
|
||||||
levelChunkPacket.setDimension(DimensionUtils.javaToBedrock(session.getChunkCache().getBedrockDimension()));
|
levelChunkPacket.setDimension(DimensionUtils.javaToBedrock(session.getBedrockDimension()));
|
||||||
session.sendUpstreamPacket(levelChunkPacket);
|
session.sendUpstreamPacket(levelChunkPacket);
|
||||||
|
|
||||||
for (Map.Entry<Vector3i, ItemFrameEntity> entry : session.getItemFrameCache().entrySet()) {
|
for (Map.Entry<Vector3i, ItemFrameEntity> entry : session.getItemFrameCache().entrySet()) {
|
||||||
|
|
|
@ -149,7 +149,7 @@ public class ChunkUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendEmptyChunk(GeyserSession session, int chunkX, int chunkZ, boolean forceUpdate) {
|
public static void sendEmptyChunk(GeyserSession session, int chunkX, int chunkZ, boolean forceUpdate) {
|
||||||
BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension();
|
BedrockDimension bedrockDimension = session.getBedrockDimension();
|
||||||
int bedrockSubChunkCount = bedrockDimension.height() >> 4;
|
int bedrockSubChunkCount = bedrockDimension.height() >> 4;
|
||||||
|
|
||||||
byte[] payload;
|
byte[] payload;
|
||||||
|
@ -167,7 +167,7 @@ public class ChunkUtils {
|
||||||
byteBuf.readBytes(payload);
|
byteBuf.readBytes(payload);
|
||||||
|
|
||||||
LevelChunkPacket data = new LevelChunkPacket();
|
LevelChunkPacket data = new LevelChunkPacket();
|
||||||
data.setDimension(DimensionUtils.javaToBedrock(session.getChunkCache().getBedrockDimension()));
|
data.setDimension(DimensionUtils.javaToBedrock(session.getBedrockDimension()));
|
||||||
data.setChunkX(chunkX);
|
data.setChunkX(chunkX);
|
||||||
data.setChunkZ(chunkZ);
|
data.setChunkZ(chunkZ);
|
||||||
data.setSubChunksLength(0);
|
data.setSubChunksLength(0);
|
||||||
|
@ -214,7 +214,7 @@ public class ChunkUtils {
|
||||||
throw new RuntimeException("Maximum Y must be a multiple of 16!");
|
throw new RuntimeException("Maximum Y must be a multiple of 16!");
|
||||||
}
|
}
|
||||||
|
|
||||||
BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension();
|
BedrockDimension bedrockDimension = session.getBedrockDimension();
|
||||||
// Yell in the console if the world height is too height in the current scenario
|
// Yell in the console if the world height is too height in the current scenario
|
||||||
// The constraints change depending on if the player is in the overworld or not, and if experimental height is enabled
|
// The constraints change depending on if the player is in the overworld or not, and if experimental height is enabled
|
||||||
// (Ignore this for the Nether. We can't change that at the moment without the workaround. :/ )
|
// (Ignore this for the Nether. We can't change that at the moment without the workaround. :/ )
|
||||||
|
|
|
@ -179,7 +179,7 @@ public class DimensionUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setBedrockDimension(GeyserSession session, int bedrockDimension) {
|
public static void setBedrockDimension(GeyserSession session, int bedrockDimension) {
|
||||||
session.getChunkCache().setBedrockDimension(switch (bedrockDimension) {
|
session.setBedrockDimension(switch (bedrockDimension) {
|
||||||
case BEDROCK_END_ID -> BedrockDimension.THE_END;
|
case BEDROCK_END_ID -> BedrockDimension.THE_END;
|
||||||
case BEDROCK_DEFAULT_NETHER_ID -> BedrockDimension.THE_NETHER; // JavaDimension *should* be set to BEDROCK_END_ID if the Nether workaround is enabled.
|
case BEDROCK_DEFAULT_NETHER_ID -> BedrockDimension.THE_NETHER; // JavaDimension *should* be set to BEDROCK_END_ID if the Nether workaround is enabled.
|
||||||
default -> BedrockDimension.OVERWORLD;
|
default -> BedrockDimension.OVERWORLD;
|
||||||
|
|
|
@ -159,7 +159,7 @@ public class InventoryUtils {
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Vector3i findAvailableWorldSpace(GeyserSession session) {
|
public static Vector3i findAvailableWorldSpace(GeyserSession session) {
|
||||||
// Check if a fake block can be placed, either above the player or beneath.
|
// Check if a fake block can be placed, either above the player or beneath.
|
||||||
BedrockDimension dimension = session.getChunkCache().getBedrockDimension();
|
BedrockDimension dimension = session.getBedrockDimension();
|
||||||
int minY = dimension.minY(), maxY = minY + dimension.height();
|
int minY = dimension.minY(), maxY = minY + dimension.height();
|
||||||
Vector3i flatPlayerPosition = session.getPlayerEntity().getPosition().toInt();
|
Vector3i flatPlayerPosition = session.getPlayerEntity().getPosition().toInt();
|
||||||
Vector3i position = flatPlayerPosition.add(Vector3i.UP);
|
Vector3i position = flatPlayerPosition.add(Vector3i.UP);
|
||||||
|
|
Loading…
Reference in a new issue