Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-12-25 15:50:14 +01:00
Emulate vanilla behavior with existing registries
Dieser Commit ist enthalten in:
Ursprung
6c4b2cb173
Commit
423d2e3a36
@ -28,35 +28,6 @@ package org.geysermc.geyser.session;
|
||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||
import com.github.steveice10.mc.auth.exception.request.RequestException;
|
||||
import com.github.steveice10.mc.auth.service.MsaAuthenticationService;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftConstants;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
|
||||
import org.geysermc.mcprotocollib.protocol.data.ProtocolState;
|
||||
import org.geysermc.mcprotocollib.protocol.data.UnexpectedEncryptionException;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.HandPreference;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.setting.ChatVisibility;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.setting.SkinPart;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.statistic.CustomStatistic;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.statistic.Statistic;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundClientInformationPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.handshake.serverbound.ClientIntentionPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatCommandSignedPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket;
|
||||
import org.geysermc.mcprotocollib.network.BuiltinFlags;
|
||||
import org.geysermc.mcprotocollib.network.Session;
|
||||
import org.geysermc.mcprotocollib.network.event.session.*;
|
||||
import org.geysermc.mcprotocollib.network.packet.Packet;
|
||||
import org.geysermc.mcprotocollib.network.tcp.TcpClientSession;
|
||||
import org.geysermc.mcprotocollib.network.tcp.TcpSession;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.EventLoop;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
@ -145,6 +116,38 @@ import org.geysermc.geyser.util.ChunkUtils;
|
||||
import org.geysermc.geyser.util.DimensionUtils;
|
||||
import org.geysermc.geyser.util.EntityUtils;
|
||||
import org.geysermc.geyser.util.LoginEncryptionUtils;
|
||||
import org.geysermc.mcprotocollib.network.BuiltinFlags;
|
||||
import org.geysermc.mcprotocollib.network.Session;
|
||||
import org.geysermc.mcprotocollib.network.event.session.*;
|
||||
import org.geysermc.mcprotocollib.network.packet.Packet;
|
||||
import org.geysermc.mcprotocollib.network.tcp.TcpClientSession;
|
||||
import org.geysermc.mcprotocollib.network.tcp.TcpSession;
|
||||
import org.geysermc.mcprotocollib.protocol.ClientListener;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftConstants;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
|
||||
import org.geysermc.mcprotocollib.protocol.data.ProtocolState;
|
||||
import org.geysermc.mcprotocollib.protocol.data.UnexpectedEncryptionException;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.HandPreference;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.setting.ChatVisibility;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.setting.SkinPart;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.statistic.CustomStatistic;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.statistic.Statistic;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundClientInformationPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundFinishConfigurationPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.configuration.serverbound.ServerboundFinishConfigurationPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.handshake.serverbound.ClientIntentionPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatCommandSignedPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetSocketAddress;
|
||||
@ -646,9 +649,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
sentSpawnPacket = true;
|
||||
syncEntityProperties();
|
||||
|
||||
// Set the hardcoded shield ID to the ID we just defined in StartGamePacket
|
||||
// upstream.getSession().getHardcodedBlockingId().set(this.itemMappings.getStoredItems().shield().getBedrockId());
|
||||
|
||||
if (GeyserImpl.getInstance().getConfig().isAddNonBedrockItems()) {
|
||||
ItemComponentPacket componentPacket = new ItemComponentPacket();
|
||||
componentPacket.getItems().addAll(itemMappings.getComponentItemData());
|
||||
@ -875,6 +875,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
// Start ticking
|
||||
tickThread = eventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS);
|
||||
|
||||
this.protocol.setUseDefaultListeners(false);
|
||||
|
||||
TcpSession downstream;
|
||||
if (geyser.getBootstrap().getSocketAddress() != null) {
|
||||
// We're going to connect through the JVM and not through TCP
|
||||
@ -904,6 +906,25 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
// Let Geyser handle sending the keep alive
|
||||
downstream.setFlag(MinecraftConstants.AUTOMATIC_KEEP_ALIVE_MANAGEMENT, false);
|
||||
}
|
||||
// We'll handle this since we have the registry data on hand
|
||||
downstream.setFlag(MinecraftConstants.SEND_BLANK_KNOWN_PACKS_RESPONSE, false);
|
||||
|
||||
// This isn't a great solution, but... we want to make sure the finish configuration packet cannot be sent
|
||||
// before the KnownPacks packet.
|
||||
this.downstream.getSession().addListener(new ClientListener(ProtocolState.LOGIN, loginEvent.transferring()) {
|
||||
@Override
|
||||
public void packetReceived(Session session, Packet packet) {
|
||||
if (protocol.getState() == ProtocolState.CONFIGURATION) {
|
||||
if (packet instanceof ClientboundFinishConfigurationPacket) {
|
||||
// Prevent
|
||||
GeyserSession.this.ensureInEventLoop(() -> GeyserSession.this.sendDownstreamPacket(new ServerboundFinishConfigurationPacket()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.packetReceived(session, packet);
|
||||
}
|
||||
});
|
||||
|
||||
downstream.addListener(new SessionAdapter() {
|
||||
@Override
|
||||
public void packetSending(PacketSendingEvent event) {
|
||||
@ -1543,8 +1564,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
startGamePacket.setEnchantmentSeed(0);
|
||||
startGamePacket.setMultiplayerCorrelationId("");
|
||||
|
||||
startGamePacket.setItemDefinitions(this.itemMappings.getItemDefinitions().values().stream().toList()); // TODO
|
||||
// startGamePacket.setBlockPalette(this.blockMappings.getBedrockBlockPalette());
|
||||
startGamePacket.getItemDefinitions().addAll(this.itemMappings.getItemDefinitions().values());
|
||||
|
||||
// Needed for custom block mappings and custom skulls system
|
||||
startGamePacket.getBlockProperties().addAll(this.blockMappings.getBlockProperties());
|
||||
|
@ -30,6 +30,8 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.TrimMaterial;
|
||||
import org.cloudburstmc.protocol.bedrock.data.TrimPattern;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
@ -42,6 +44,7 @@ import org.geysermc.geyser.session.cache.registry.JavaRegistry;
|
||||
import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry;
|
||||
import org.geysermc.geyser.text.TextDecoration;
|
||||
import org.geysermc.geyser.translator.level.BiomeTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket;
|
||||
|
||||
@ -63,6 +66,7 @@ import java.util.function.ToIntFunction;
|
||||
@Accessors(fluent = true)
|
||||
@Getter
|
||||
public final class RegistryCache {
|
||||
private static final Map<String, Map<String, NbtMap>> DEFAULTS;
|
||||
private static final Map<String, BiConsumer<RegistryCache, List<RegistryEntry>>> REGISTRIES = new HashMap<>();
|
||||
|
||||
static {
|
||||
@ -73,6 +77,24 @@ public final class RegistryCache {
|
||||
register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome);
|
||||
register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId()));
|
||||
register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.WolfVariant.getByJavaIdentifier(entry.getId()));
|
||||
|
||||
// Load from MCProtocolLib's classloader
|
||||
NbtMap tag = MinecraftProtocol.loadNetworkCodec();
|
||||
Map<String, Map<String, NbtMap>> defaults = new HashMap<>();
|
||||
// Don't create a keySet - no need to create the cached object in HashMap if we don't use it again
|
||||
REGISTRIES.forEach((key, $) -> {
|
||||
List<NbtMap> rawValues = tag.getCompound(key)
|
||||
.getList("value", NbtType.COMPOUND);
|
||||
Map<String, NbtMap> values = new HashMap<>();
|
||||
for (NbtMap value : rawValues) {
|
||||
String name = value.getString("name");
|
||||
values.put(name, value.getCompound("element"));
|
||||
}
|
||||
// Can make these maps immutable and as efficient as possible after initialization
|
||||
defaults.put(key, Map.copyOf(values));
|
||||
});
|
||||
|
||||
DEFAULTS = Map.copyOf(defaults);
|
||||
}
|
||||
|
||||
@Getter(AccessLevel.NONE)
|
||||
@ -116,13 +138,22 @@ public final class RegistryCache {
|
||||
* @param <T> the class that represents these entries.
|
||||
*/
|
||||
private static <T> void register(String registry, Function<RegistryCache, JavaRegistry<T>> localCacheFunction, BiFunction<GeyserSession, RegistryEntry, T> reader) {
|
||||
REGISTRIES.put("minecraft:" + registry, (registryCache, entries) -> {
|
||||
String key = "minecraft:" + registry;
|
||||
REGISTRIES.put(key, (registryCache, entries) -> {
|
||||
Map<String, NbtMap> localRegistry = null;
|
||||
JavaRegistry<T> localCache = localCacheFunction.apply(registryCache);
|
||||
// Clear each local cache every time a new registry entry is given to us
|
||||
// (e.g. proxy server switches)
|
||||
List<T> builder = new ArrayList<>(entries.size());
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
RegistryEntry entry = entries.get(i);
|
||||
// If the data is null, that's the server telling us we need to use our default values.
|
||||
if (entry.getData() == null) {
|
||||
if (localRegistry == null) { // Lazy initialize
|
||||
localRegistry = DEFAULTS.get(key);
|
||||
}
|
||||
entry = new RegistryEntry(entry.getId(), localRegistry.get(entry.getId()));
|
||||
}
|
||||
// This is what Geyser wants to keep as a value for this registry.
|
||||
T cacheEntry = reader.apply(registryCache.session, entry);
|
||||
builder.add(i, cacheEntry);
|
||||
@ -156,4 +187,8 @@ public final class RegistryCache {
|
||||
localCacheFunction.accept(registryCache, array);
|
||||
});
|
||||
}
|
||||
|
||||
public static void init() {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren