Start on block remapping, send ServerboundPlayerLoadedPacket on respawn/new logins

This commit is contained in:
onebeastchris 2024-12-04 20:46:38 +08:00
parent db246ffb3b
commit ee5c0e6853
10 changed files with 222 additions and 75 deletions

View file

@ -71,6 +71,10 @@ dependencies {
api(libs.events) api(libs.events)
} }
tasks.test {
enabled = false
}
tasks.processResources { tasks.processResources {
// This is solely for backwards compatibility for other programs that used this file before the switch to gradle. // This is solely for backwards compatibility for other programs that used this file before the switch to gradle.
// It used to be generated by the maven Git-Commit-Id-Plugin // It used to be generated by the maven Git-Commit-Id-Plugin

View file

@ -116,6 +116,7 @@ import org.geysermc.geyser.entity.type.living.monster.BasePiglinEntity;
import org.geysermc.geyser.entity.type.living.monster.BlazeEntity; import org.geysermc.geyser.entity.type.living.monster.BlazeEntity;
import org.geysermc.geyser.entity.type.living.monster.BoggedEntity; import org.geysermc.geyser.entity.type.living.monster.BoggedEntity;
import org.geysermc.geyser.entity.type.living.monster.BreezeEntity; import org.geysermc.geyser.entity.type.living.monster.BreezeEntity;
import org.geysermc.geyser.entity.type.living.monster.CreakingEntity;
import org.geysermc.geyser.entity.type.living.monster.CreeperEntity; import org.geysermc.geyser.entity.type.living.monster.CreeperEntity;
import org.geysermc.geyser.entity.type.living.monster.ElderGuardianEntity; import org.geysermc.geyser.entity.type.living.monster.ElderGuardianEntity;
import org.geysermc.geyser.entity.type.living.monster.EnderDragonEntity; import org.geysermc.geyser.entity.type.living.monster.EnderDragonEntity;
@ -179,6 +180,7 @@ public final class EntityDefinitions {
public static final EntityDefinition<AbstractFishEntity> COD; public static final EntityDefinition<AbstractFishEntity> COD;
public static final EntityDefinition<CommandBlockMinecartEntity> COMMAND_BLOCK_MINECART; public static final EntityDefinition<CommandBlockMinecartEntity> COMMAND_BLOCK_MINECART;
public static final EntityDefinition<CowEntity> COW; public static final EntityDefinition<CowEntity> COW;
public static final EntityDefinition<CreakingEntity> CREAKING;
public static final EntityDefinition<CreeperEntity> CREEPER; public static final EntityDefinition<CreeperEntity> CREEPER;
public static final EntityDefinition<BoatEntity> DARK_OAK_BOAT; public static final EntityDefinition<BoatEntity> DARK_OAK_BOAT;
public static final EntityDefinition<ChestBoatEntity> DARK_OAK_CHEST_BOAT; public static final EntityDefinition<ChestBoatEntity> DARK_OAK_CHEST_BOAT;
@ -671,6 +673,14 @@ public final class EntityDefinitions {
.type(EntityType.BREEZE) .type(EntityType.BREEZE)
.height(1.77f).width(0.6f) .height(1.77f).width(0.6f)
.build(); .build();
CREAKING = EntityDefinition.inherited(CreakingEntity::new, mobEntityBase)
.type(EntityType.CREAKING)
.height(2.7f).width(0.9f)
.addTranslator(MetadataType.BOOLEAN, CreakingEntity::setCanMove)
.addTranslator(MetadataType.BOOLEAN, CreakingEntity::setActive)
.addTranslator(MetadataType.BOOLEAN, CreakingEntity::setIsTearingDown)
.addTranslator(MetadataType.OPTIONAL_POSITION, CreakingEntity::setHomePos)
.build();
CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase) CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase)
.type(EntityType.CREEPER) .type(EntityType.CREEPER)
.height(1.7f).width(0.6f) .height(1.7f).width(0.6f)

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.entity.type.living.monster;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType;
import java.util.Optional;
import java.util.UUID;
public class CreakingEntity extends MonsterEntity {
public CreakingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
public void setCanMove(EntityMetadata<Boolean,? extends MetadataType<Boolean>> booleanEntityMetadata) {
}
public void setActive(EntityMetadata<Boolean,? extends MetadataType<Boolean>> booleanEntityMetadata) {
}
public void setIsTearingDown(EntityMetadata<Boolean,? extends MetadataType<Boolean>> booleanEntityMetadata) {
}
public void setHomePos(EntityMetadata<Optional<Vector3i>,? extends MetadataType<Optional<Vector3i>>> optionalEntityMetadata) {
}
}

View file

@ -58,7 +58,6 @@ import org.geysermc.geyser.level.block.property.Properties;
import org.geysermc.geyser.level.block.type.Block; import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.block.type.BlockState; import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.block.type.FlowerPotBlock; import org.geysermc.geyser.level.block.type.FlowerPotBlock;
import org.geysermc.geyser.level.block.type.SkullBlock;
import org.geysermc.geyser.level.physics.PistonBehavior; import org.geysermc.geyser.level.physics.PistonBehavior;
import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.Registries;
@ -66,7 +65,6 @@ import org.geysermc.geyser.registry.type.BlockMappings;
import org.geysermc.geyser.registry.type.GeyserBedrockBlock; import org.geysermc.geyser.registry.type.GeyserBedrockBlock;
import org.geysermc.geyser.util.BlockUtils; import org.geysermc.geyser.util.BlockUtils;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.InputStream; import java.io.InputStream;
@ -125,8 +123,8 @@ public final class BlockRegistryPopulator {
private static void registerBedrockBlocks() { private static void registerBedrockBlocks() {
var blockMappers = ImmutableMap.<ObjectIntPair<String>, Remapper>builder() var blockMappers = ImmutableMap.<ObjectIntPair<String>, Remapper>builder()
.put(ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), faultyStrippedWoodRemapper()) .put(ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), Conversion766_748::remapBlock)
.put(ObjectIntPair.of("1_21_50", Bedrock_v765.CODEC.getProtocolVersion()), faultyStrippedWoodRemapper()) .put(ObjectIntPair.of("1_21_50", Bedrock_v765.CODEC.getProtocolVersion()), tag -> tag)
.build(); .build();
// We can keep this strong as nothing should be garbage collected // We can keep this strong as nothing should be garbage collected
@ -259,15 +257,6 @@ public final class BlockRegistryPopulator {
NbtMap originalBedrockTag = buildBedrockState(blockState, entry); NbtMap originalBedrockTag = buildBedrockState(blockState, entry);
NbtMap bedrockTag = stateMapper.remap(originalBedrockTag); NbtMap bedrockTag = stateMapper.remap(originalBedrockTag);
// FIXME TEMPORARY
if (blockState.block() instanceof SkullBlock && palette.valueInt() >= Bedrock_v748.CODEC.getProtocolVersion()) {
// The flattening must be a very interesting process.
String skullName = blockState.block().javaIdentifier().asString().replace("_wall", "");
bedrockTag = bedrockTag.toBuilder()
.putString("name", skullName)
.build();
}
GeyserBedrockBlock vanillaBedrockDefinition = blockStateOrderedMap.get(bedrockTag); GeyserBedrockBlock vanillaBedrockDefinition = blockStateOrderedMap.get(bedrockTag);
GeyserBedrockBlock bedrockDefinition; GeyserBedrockBlock bedrockDefinition;
@ -413,19 +402,6 @@ public final class BlockRegistryPopulator {
} }
} }
private static @NotNull Remapper faultyStrippedWoodRemapper() {
return tag -> {
final String name = tag.getString("name");
if (name.endsWith("_wood") && tag.getCompound("states").containsKey("stripped_bit")) {
NbtMapBuilder builder = tag.getCompound("states").toBuilder();
builder.remove("stripped_bit");
NbtMap states = builder.build();
return tag.toBuilder().putCompound("states", states).build();
}
return tag;
};
}
private static void registerJavaBlocks() { private static void registerJavaBlocks() {
List<NbtMap> blocksNbt; List<NbtMap> blocksNbt;
try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/blocks.nbt")) { try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResourceOrThrow("mappings/blocks.nbt")) {

View file

@ -1,48 +0,0 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.registry.populator;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.type.GeyserMappingItem;
import java.util.Map;
public class Conversion748_729 {
private static final Map<String, Integer> NEW_PLAYER_HEADS = Map.of("minecraft:skeleton_skull", 0, "minecraft:wither_skeleton_skull", 1, "minecraft:zombie_head", 2, "minecraft:player_head", 3, "minecraft:creeper_head", 4, "minecraft:dragon_head", 5, "minecraft:piglin_head", 6);
static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) {
String identifier = mapping.getBedrockIdentifier();
if (NEW_PLAYER_HEADS.containsKey(identifier)) {
return mapping.withBedrockIdentifier("minecraft:skull")
.withBedrockData(NEW_PLAYER_HEADS.get(identifier));
}
return mapping;
}
}

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.registry.populator;
import io.jsonwebtoken.lang.Collections;
import org.cloudburstmc.nbt.NbtMap;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.Blocks;
import java.util.ArrayList;
import java.util.List;
public class Conversion766_748 {
static List<String> newBlockIds = new ArrayList<>();
static List<String> bedrockIds = new ArrayList<>(); // TODO temp remove
static {
var blocks = Collections.of(
Blocks.PALE_OAK_WOOD,
Blocks.PALE_OAK_PLANKS,
Blocks.PALE_OAK_SAPLING,
Blocks.PALE_OAK_LOG,
Blocks.STRIPPED_PALE_OAK_LOG,
Blocks.STRIPPED_PALE_OAK_WOOD,
Blocks.PALE_OAK_LEAVES,
Blocks.PALE_OAK_SIGN,
Blocks.PALE_OAK_WALL_SIGN,
Blocks.PALE_OAK_HANGING_SIGN,
Blocks.PALE_OAK_WALL_HANGING_SIGN,
Blocks.PALE_OAK_PRESSURE_PLATE,
Blocks.PALE_OAK_TRAPDOOR,
Blocks.POTTED_PALE_OAK_SAPLING,
Blocks.PALE_OAK_BUTTON,
Blocks.PALE_OAK_STAIRS,
Blocks.PALE_OAK_SLAB,
Blocks.PALE_OAK_FENCE_GATE,
Blocks.PALE_OAK_FENCE,
Blocks.PALE_OAK_DOOR,
Blocks.PALE_MOSS_BLOCK,
Blocks.PALE_MOSS_CARPET,
Blocks.PALE_HANGING_MOSS,
Blocks.OPEN_EYEBLOSSOM,
Blocks.CLOSED_EYEBLOSSOM,
Blocks.POTTED_OPEN_EYEBLOSSOM,
Blocks.POTTED_CLOSED_EYEBLOSSOM,
Blocks.RESIN_CLUMP,
Blocks.RESIN_BLOCK,
Blocks.RESIN_BRICKS,
Blocks.RESIN_BRICK_STAIRS,
Blocks.RESIN_BRICK_SLAB,
Blocks.RESIN_BRICK_WALL,
Blocks.CHISELED_RESIN_BRICKS,
Blocks.CREAKING_HEART
);
blocks.forEach(block -> newBlockIds.add(block.javaIdentifier().value()));
}
static NbtMap remapBlock(NbtMap tag) {
GeyserImpl.getInstance().getLogger().info(tag.toString());
String name = tag.getString("name");
if (newBlockIds.contains(name)) {
bedrockIds.add(name);
// TODO
return tag.toBuilder()
.putCompound("states", NbtMap.builder().build())
.putString("name", "minecraft:unknown")
.build();
}
if (name.contains("resin") || name.contains("creaking") || name.contains("pale")) {
throw new RuntimeException("ya missed " + name);
}
return tag;
}
}

View file

@ -82,6 +82,7 @@ import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -107,8 +108,45 @@ public class ItemRegistryPopulator {
} }
public static void populate() { public static void populate() {
Map<Item, Item> itemFallbacks = new HashMap<>();
itemFallbacks.put(Items.PALE_OAK_PLANKS, Items.BIRCH_PLANKS);
itemFallbacks.put(Items.PALE_OAK_FENCE, Items.BIRCH_FENCE);
itemFallbacks.put(Items.PALE_OAK_FENCE_GATE, Items.BIRCH_FENCE_GATE);
itemFallbacks.put(Items.PALE_OAK_STAIRS, Items.BIRCH_STAIRS);
itemFallbacks.put(Items.PALE_OAK_DOOR, Items.BIRCH_DOOR);
itemFallbacks.put(Items.PALE_OAK_TRAPDOOR, Items.BIRCH_TRAPDOOR);
itemFallbacks.put(Items.PALE_OAK_SLAB, Items.BIRCH_SLAB);
itemFallbacks.put(Items.PALE_OAK_LOG, Items.BIRCH_LOG);
itemFallbacks.put(Items.STRIPPED_PALE_OAK_LOG, Items.STRIPPED_BIRCH_LOG);
itemFallbacks.put(Items.PALE_OAK_WOOD, Items.BIRCH_WOOD);
itemFallbacks.put(Items.PALE_OAK_LEAVES, Items.BIRCH_LEAVES);
itemFallbacks.put(Items.PALE_OAK_SAPLING, Items.BIRCH_SAPLING);
itemFallbacks.put(Items.STRIPPED_PALE_OAK_WOOD, Items.STRIPPED_BIRCH_WOOD);
itemFallbacks.put(Items.PALE_OAK_SIGN, Items.BIRCH_SIGN);
itemFallbacks.put(Items.PALE_OAK_HANGING_SIGN, Items.BIRCH_HANGING_SIGN);
itemFallbacks.put(Items.PALE_OAK_BOAT, Items.BIRCH_BOAT);
itemFallbacks.put(Items.PALE_OAK_CHEST_BOAT, Items.BIRCH_CHEST_BOAT);
itemFallbacks.put(Items.PALE_OAK_BUTTON, Items.BIRCH_BUTTON);
itemFallbacks.put(Items.PALE_OAK_PRESSURE_PLATE, Items.BIRCH_PRESSURE_PLATE);
itemFallbacks.put(Items.RESIN_CLUMP, Items.RAW_COPPER);
itemFallbacks.put(Items.RESIN_BRICK_WALL, Items.RED_SANDSTONE_WALL);
itemFallbacks.put(Items.RESIN_BRICK_STAIRS, Items.RED_SANDSTONE_STAIRS);
itemFallbacks.put(Items.RESIN_BRICK_SLAB, Items.RED_SANDSTONE_SLAB);
itemFallbacks.put(Items.RESIN_BLOCK, Items.RED_SANDSTONE);
itemFallbacks.put(Items.RESIN_BRICK, Items.BRICK);
itemFallbacks.put(Items.RESIN_BRICKS, Items.CUT_RED_SANDSTONE);
itemFallbacks.put(Items.CHISELED_RESIN_BRICKS, Items.CHISELED_RED_SANDSTONE);
itemFallbacks.put(Items.CLOSED_EYEBLOSSOM, Items.WHITE_TULIP);
itemFallbacks.put(Items.OPEN_EYEBLOSSOM, Items.OXEYE_DAISY);
itemFallbacks.put(Items.PALE_MOSS_BLOCK, Items.MOSS_BLOCK);
itemFallbacks.put(Items.PALE_MOSS_CARPET, Items.MOSS_CARPET);
itemFallbacks.put(Items.PALE_HANGING_MOSS, Items.HANGING_ROOTS);
itemFallbacks.put(Items.CREAKING_HEART, Items.CHISELED_POLISHED_BLACKSTONE);
itemFallbacks.put(Items.CREAKING_SPAWN_EGG, Items.HOGLIN_SPAWN_EGG);
List<PaletteVersion> paletteVersions = new ArrayList<>(2); List<PaletteVersion> paletteVersions = new ArrayList<>(2);
paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion())); paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion(), itemFallbacks, (item, mapping) -> mapping));
paletteVersions.add(new PaletteVersion("1_21_50", Bedrock_v765.CODEC.getProtocolVersion())); paletteVersions.add(new PaletteVersion("1_21_50", Bedrock_v765.CODEC.getProtocolVersion()));
GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap();

View file

@ -40,6 +40,7 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.Serverbound
public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslator<SetLocalPlayerAsInitializedPacket> { public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslator<SetLocalPlayerAsInitializedPacket> {
@Override @Override
public void translate(GeyserSession session, SetLocalPlayerAsInitializedPacket packet) { public void translate(GeyserSession session, SetLocalPlayerAsInitializedPacket packet) {
GeyserImpl.getInstance().getLogger().info(packet.toString());
if (session.getPlayerEntity().getGeyserId() == packet.getRuntimeEntityId()) { if (session.getPlayerEntity().getGeyserId() == packet.getRuntimeEntityId()) {
if (!session.getUpstream().isInitialized()) { if (!session.getUpstream().isInitialized()) {
session.getUpstream().setInitialized(true); session.getUpstream().setInitialized(true);

View file

@ -45,6 +45,7 @@ import org.geysermc.geyser.util.MinecraftKey;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo;
import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundLoginPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundLoginPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundPlayerLoadedPacket;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
@ -128,5 +129,9 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
} }
ChunkUtils.loadDimension(session); ChunkUtils.loadDimension(session);
if (!needsSpawnPacket) {
session.sendDownstreamGamePacket(ServerboundPlayerLoadedPacket.INSTANCE);
}
} }
} }

View file

@ -38,6 +38,7 @@ import org.geysermc.geyser.util.DimensionUtils;
import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundRespawnPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundRespawnPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundPlayerLoadedPacket;
@Translator(packet = ClientboundRespawnPacket.class) @Translator(packet = ClientboundRespawnPacket.class)
public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPacket> { public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPacket> {
@ -93,5 +94,7 @@ public class JavaRespawnTranslator extends PacketTranslator<ClientboundRespawnPa
ChunkUtils.loadDimension(session); ChunkUtils.loadDimension(session);
} }
session.sendDownstreamGamePacket(ServerboundPlayerLoadedPacket.INSTANCE);
} }
} }