Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-12-26 00:00:41 +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.data.GameProfile;
|
||||||
import com.github.steveice10.mc.auth.exception.request.RequestException;
|
import com.github.steveice10.mc.auth.exception.request.RequestException;
|
||||||
import com.github.steveice10.mc.auth.service.MsaAuthenticationService;
|
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.Channel;
|
||||||
import io.netty.channel.EventLoop;
|
import io.netty.channel.EventLoop;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
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.DimensionUtils;
|
||||||
import org.geysermc.geyser.util.EntityUtils;
|
import org.geysermc.geyser.util.EntityUtils;
|
||||||
import org.geysermc.geyser.util.LoginEncryptionUtils;
|
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.ConnectException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
@ -646,9 +649,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||||||
sentSpawnPacket = true;
|
sentSpawnPacket = true;
|
||||||
syncEntityProperties();
|
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()) {
|
if (GeyserImpl.getInstance().getConfig().isAddNonBedrockItems()) {
|
||||||
ItemComponentPacket componentPacket = new ItemComponentPacket();
|
ItemComponentPacket componentPacket = new ItemComponentPacket();
|
||||||
componentPacket.getItems().addAll(itemMappings.getComponentItemData());
|
componentPacket.getItems().addAll(itemMappings.getComponentItemData());
|
||||||
@ -875,6 +875,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||||||
// Start ticking
|
// Start ticking
|
||||||
tickThread = eventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS);
|
tickThread = eventLoop.scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
this.protocol.setUseDefaultListeners(false);
|
||||||
|
|
||||||
TcpSession downstream;
|
TcpSession downstream;
|
||||||
if (geyser.getBootstrap().getSocketAddress() != null) {
|
if (geyser.getBootstrap().getSocketAddress() != null) {
|
||||||
// We're going to connect through the JVM and not through TCP
|
// 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
|
// Let Geyser handle sending the keep alive
|
||||||
downstream.setFlag(MinecraftConstants.AUTOMATIC_KEEP_ALIVE_MANAGEMENT, false);
|
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() {
|
downstream.addListener(new SessionAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void packetSending(PacketSendingEvent event) {
|
public void packetSending(PacketSendingEvent event) {
|
||||||
@ -1543,8 +1564,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||||||
startGamePacket.setEnchantmentSeed(0);
|
startGamePacket.setEnchantmentSeed(0);
|
||||||
startGamePacket.setMultiplayerCorrelationId("");
|
startGamePacket.setMultiplayerCorrelationId("");
|
||||||
|
|
||||||
startGamePacket.setItemDefinitions(this.itemMappings.getItemDefinitions().values().stream().toList()); // TODO
|
startGamePacket.getItemDefinitions().addAll(this.itemMappings.getItemDefinitions().values());
|
||||||
// startGamePacket.setBlockPalette(this.blockMappings.getBedrockBlockPalette());
|
|
||||||
|
|
||||||
// Needed for custom block mappings and custom skulls system
|
// Needed for custom block mappings and custom skulls system
|
||||||
startGamePacket.getBlockProperties().addAll(this.blockMappings.getBlockProperties());
|
startGamePacket.getBlockProperties().addAll(this.blockMappings.getBlockProperties());
|
||||||
|
@ -30,6 +30,8 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
|||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.experimental.Accessors;
|
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.TrimMaterial;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.TrimPattern;
|
import org.cloudburstmc.protocol.bedrock.data.TrimPattern;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
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.session.cache.registry.SimpleJavaRegistry;
|
||||||
import org.geysermc.geyser.text.TextDecoration;
|
import org.geysermc.geyser.text.TextDecoration;
|
||||||
import org.geysermc.geyser.translator.level.BiomeTranslator;
|
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.data.game.RegistryEntry;
|
||||||
import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket;
|
import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket;
|
||||||
|
|
||||||
@ -63,6 +66,7 @@ import java.util.function.ToIntFunction;
|
|||||||
@Accessors(fluent = true)
|
@Accessors(fluent = true)
|
||||||
@Getter
|
@Getter
|
||||||
public final class RegistryCache {
|
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<>();
|
private static final Map<String, BiConsumer<RegistryCache, List<RegistryEntry>>> REGISTRIES = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
@ -73,6 +77,24 @@ public final class RegistryCache {
|
|||||||
register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome);
|
register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome);
|
||||||
register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId()));
|
register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId()));
|
||||||
register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.WolfVariant.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)
|
@Getter(AccessLevel.NONE)
|
||||||
@ -116,13 +138,22 @@ public final class RegistryCache {
|
|||||||
* @param <T> the class that represents these entries.
|
* @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) {
|
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);
|
JavaRegistry<T> localCache = localCacheFunction.apply(registryCache);
|
||||||
// Clear each local cache every time a new registry entry is given to us
|
// Clear each local cache every time a new registry entry is given to us
|
||||||
// (e.g. proxy server switches)
|
// (e.g. proxy server switches)
|
||||||
List<T> builder = new ArrayList<>(entries.size());
|
List<T> builder = new ArrayList<>(entries.size());
|
||||||
for (int i = 0; i < entries.size(); i++) {
|
for (int i = 0; i < entries.size(); i++) {
|
||||||
RegistryEntry entry = entries.get(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.
|
// This is what Geyser wants to keep as a value for this registry.
|
||||||
T cacheEntry = reader.apply(registryCache.session, entry);
|
T cacheEntry = reader.apply(registryCache.session, entry);
|
||||||
builder.add(i, cacheEntry);
|
builder.add(i, cacheEntry);
|
||||||
@ -156,4 +187,8 @@ public final class RegistryCache {
|
|||||||
localCacheFunction.accept(registryCache, array);
|
localCacheFunction.accept(registryCache, array);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren