Merge branch 'master' into feature/protocol-3.0

This commit is contained in:
SupremeMortal 2023-02-14 22:09:48 +00:00
commit 1769f2a85c
No known key found for this signature in database
GPG key ID: DDBB25F8EE4FA29A
117 changed files with 12195 additions and 1369 deletions

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2019-2021 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.platform.spigot;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import org.bukkit.Bukkit;
import org.geysermc.geyser.GeyserImpl;
/**
* Disables the compression packet (and the compression handlers from being added to the pipeline) for Geyser clients
* that won't be receiving the data over the network.
*
* As of 1.8 - 1.17.1, compression is enabled in the Netty pipeline by adding a listener after a packet is written.
* If we simply "cancel" or don't forward the packet, then the listener is never called.
*/
public class GeyserSpigotCompressionDisabler extends ChannelOutboundHandlerAdapter {
static final boolean ENABLED;
private static final Class<?> COMPRESSION_PACKET_CLASS;
private static final Class<?> LOGIN_SUCCESS_PACKET_CLASS;
private static final boolean PROTOCOL_SUPPORT_INSTALLED;
static {
PROTOCOL_SUPPORT_INSTALLED = Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null;
Class<?> compressionPacketClass = null;
Class<?> loginSuccessPacketClass = null;
boolean enabled = false;
try {
compressionPacketClass = findCompressionPacket();
loginSuccessPacketClass = findLoginSuccessPacket();
enabled = true;
} catch (Exception e) {
GeyserImpl.getInstance().getLogger().error("Could not initialize compression disabler!", e);
}
COMPRESSION_PACKET_CLASS = compressionPacketClass;
LOGIN_SUCCESS_PACKET_CLASS = loginSuccessPacketClass;
ENABLED = enabled;
}
public GeyserSpigotCompressionDisabler() {
if (!ENABLED) {
throw new RuntimeException("Geyser compression disabler cannot be initialized in its current state!");
}
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
Class<?> msgClass = msg.getClass();
// Don't let any compression packet get through
if (!COMPRESSION_PACKET_CLASS.isAssignableFrom(msgClass)) {
if (LOGIN_SUCCESS_PACKET_CLASS.isAssignableFrom(msgClass)) {
if (PROTOCOL_SUPPORT_INSTALLED) {
// ProtocolSupport must send the compression packet, so let's remove what it did before it does damage
if (ctx.pipeline().get("compress") != null) {
ctx.pipeline().remove("compress");
}
if (ctx.pipeline().get("decompress") != null) {
ctx.pipeline().remove("decompress");
}
}
// We're past the point that a compression packet can be sent, so we can safely yeet ourselves away
ctx.channel().pipeline().remove(this);
}
super.write(ctx, msg, promise);
} else if (PROTOCOL_SUPPORT_INSTALLED) {
// We must indicate it "succeeded" or ProtocolSupport will time us out
promise.setSuccess();
}
}
private static Class<?> findCompressionPacket() throws ClassNotFoundException {
try {
return Class.forName("net.minecraft.network.protocol.login.PacketLoginOutSetCompression");
} catch (ClassNotFoundException e) {
String prefix = Bukkit.getServer().getClass().getPackage().getName().replace("org.bukkit.craftbukkit", "net.minecraft.server");
return Class.forName(prefix + ".PacketLoginOutSetCompression");
}
}
private static Class<?> findLoginSuccessPacket() throws ClassNotFoundException {
try {
return Class.forName("net.minecraft.network.protocol.login.PacketLoginOutSuccess");
} catch (ClassNotFoundException e) {
String prefix = Bukkit.getServer().getClass().getPackage().getName().replace("org.bukkit.craftbukkit", "net.minecraft.server");
return Class.forName(prefix + ".PacketLoginOutSuccess");
}
}
}

View file

@ -115,10 +115,14 @@ public class GeyserSpigotInjector extends GeyserInjector {
ChannelFuture channelFuture = (new ServerBootstrap()
.channel(LocalServerChannelWrapper.class)
.childHandler(new ChannelInitializer<Channel>() {
.childHandler(new ChannelInitializer<>() {
@Override
protected void initChannel(Channel ch) throws Exception {
initChannel.invoke(childHandler, ch);
if (bootstrap.getGeyserConfig().isDisableCompression() && GeyserSpigotCompressionDisabler.ENABLED) {
ch.pipeline().addAfter("encoder", "geyser-compression-disabler", new GeyserSpigotCompressionDisabler());
}
}
})
// Set to MAX_PRIORITY as MultithreadEventLoopGroup#newDefaultThreadFactory which DefaultEventLoopGroup implements does by default

View file

@ -195,6 +195,9 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
geyserConfig.loadFloodgate(this);
this.geyserCommandManager = new GeyserSpigotCommandManager(geyser);
this.geyserCommandManager.init();
if (!INITIALIZED) {
// Needs to be an anonymous inner class otherwise Bukkit complains about missing classes
Bukkit.getPluginManager().registerEvents(new Listener() {
@ -206,9 +209,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
}
}, this);
this.geyserCommandManager = new GeyserSpigotCommandManager(geyser);
this.geyserCommandManager.init();
// Because Bukkit locks its command map upon startup, we need to
// add our plugin commands in onEnable, but populating the executor
// can happen at any time

View file

@ -25,21 +25,18 @@
package org.geysermc.geyser.platform.spigot.world.manager;
import org.cloudburstmc.math.vector.Vector3i;
<<<<<<< HEAD
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
=======
>>>>>>> d1febe0b3904d52cdc6301711950f22d1caf09b5
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.Lectern;
import org.bukkit.block.*;
import org.bukkit.block.banner.Pattern;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BookMeta;
import org.bukkit.plugin.Plugin;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.nbt.NbtType;
@ -49,10 +46,14 @@ import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator;
import org.geysermc.geyser.translator.inventory.item.nbt.BannerTranslator;
import org.geysermc.geyser.util.BlockEntityUtils;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* The base world manager to use when there is no supported NMS revision
@ -179,6 +180,46 @@ public class GeyserSpigotWorldManager extends WorldManager {
return Bukkit.getPlayer(session.getPlayerEntity().getUsername()).hasPermission(permission);
}
@Nonnull
@Override
public CompletableFuture<@Nullable CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) {
CompletableFuture<@Nullable CompoundTag> future = new CompletableFuture<>();
// Paper 1.19.3 complains about async access otherwise.
// java.lang.IllegalStateException: Tile is null, asynchronous access?
Bukkit.getScheduler().runTask(this.plugin, () -> {
Player bukkitPlayer;
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) {
future.complete(null);
return;
}
Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
BlockState state = block.getState();
if (state instanceof Banner banner) {
ListTag list = new ListTag("Patterns");
for (int i = 0; i < banner.numberOfPatterns(); i++) {
Pattern pattern = banner.getPattern(i);
list.add(BannerTranslator.getJavaPatternTag(pattern.getPattern().getIdentifier(), pattern.getColor().ordinal()));
}
CompoundTag root = addToBlockEntityTag(list);
future.complete(root);
return;
}
future.complete(null);
});
return future;
}
private CompoundTag addToBlockEntityTag(Tag tag) {
CompoundTag compoundTag = new CompoundTag("");
CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag");
blockEntityTag.put(tag);
compoundTag.put(blockEntityTag);
return compoundTag;
}
/**
* This should be set to true if we are post-1.13 but before the latest version, and we should convert the old block state id
* to the current one.