mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Merge 6e0ded832a
into d3ea65196b
This commit is contained in:
commit
c85b1efc20
10 changed files with 273 additions and 99 deletions
|
@ -28,6 +28,7 @@ package org.geysermc.geyser.entity;
|
|||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.cloudburstmc.protocol.bedrock.data.EmoteFlag;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EmotePacket;
|
||||
import org.geysermc.geyser.api.entity.EntityData;
|
||||
import org.geysermc.geyser.api.entity.type.GeyserEntity;
|
||||
|
@ -71,6 +72,8 @@ public class GeyserEntityData implements EntityData {
|
|||
packet.setXuid("");
|
||||
packet.setPlatformId(""); // BDS sends empty
|
||||
packet.setEmoteId(emoteId);
|
||||
packet.getFlags().add(EmoteFlag.SERVER_SIDE);
|
||||
packet.getFlags().add(EmoteFlag.MUTE_EMOTE_CHAT);
|
||||
session.sendUpstreamPacket(packet);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,13 +33,20 @@ import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobArmorEquipment
|
|||
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.MobEquipmentSerializer_v291;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.PlayerHotbarSerializer_v291;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.SetEntityLinkSerializer_v291;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v291.serializer.SetEntityMotionSerializer_v291;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v390.serializer.PlayerSkinSerializer_v390;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v407.serializer.InventoryContentSerializer_v407;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v407.serializer.InventorySlotSerializer_v407;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v422.serializer.FilterTextSerializer_v422;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v486.serializer.BossEventSerializer_v486;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v554.serializer.TextSerializer_v554;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v557.serializer.SetEntityDataSerializer_v557;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v567.serializer.CommandRequestSerializer_v567;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v630.serializer.SetPlayerInventoryOptionsSerializer_v360;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v662.serializer.SetEntityMotionSerializer_v662;
|
||||
import org.cloudburstmc.protocol.bedrock.codec.v685.serializer.TextSerializer_v685;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.InventoryLayout;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.InventoryTabLeft;
|
||||
import org.cloudburstmc.protocol.bedrock.data.inventory.InventoryTabRight;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.AnvilDamagePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BossEventPacket;
|
||||
|
@ -48,11 +55,14 @@ import org.cloudburstmc.protocol.bedrock.packet.ClientCacheStatusPacket;
|
|||
import org.cloudburstmc.protocol.bedrock.packet.ClientCheatAbilityPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ClientToServerHandshakePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.CodeBuilderSourcePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.CommandRequestPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.CraftingEventPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.CreatePhotoPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.DebugInfoPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EditorNetworkPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EmoteListPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EntityFallPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.FilterTextPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.GameTestRequestPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket;
|
||||
|
@ -74,10 +84,12 @@ import org.cloudburstmc.protocol.bedrock.packet.ScriptMessagePacket;
|
|||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetPlayerInventoryOptionsPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SettingsCommandPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SimpleEventPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SubChunkRequestPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SubClientLoginPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.TextPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.TickSyncPacket;
|
||||
import org.cloudburstmc.protocol.common.util.VarInts;
|
||||
|
||||
|
@ -136,6 +148,84 @@ class CodecProcessor {
|
|||
}
|
||||
};
|
||||
|
||||
private static final BedrockPacketSerializer<SetPlayerInventoryOptionsPacket> SET_PLAYER_INVENTORY_OPTIONS_SERIALIZER = new SetPlayerInventoryOptionsSerializer_v360() {
|
||||
@Override
|
||||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, SetPlayerInventoryOptionsPacket packet) {
|
||||
int leftTabIndex = VarInts.readInt(buffer);
|
||||
int rightTabIndex = VarInts.readInt(buffer);
|
||||
|
||||
packet.setLeftTab(leftTabIndex >= 0 && leftTabIndex < InventoryTabLeft.VALUES.length ? InventoryTabLeft.VALUES[leftTabIndex] : InventoryTabLeft.NONE);
|
||||
packet.setRightTab(rightTabIndex >= 0 && rightTabIndex < InventoryTabRight.VALUES.length ? InventoryTabRight.VALUES[rightTabIndex] : InventoryTabRight.NONE);
|
||||
|
||||
packet.setFiltering(buffer.readBoolean());
|
||||
|
||||
int layoutIndex = VarInts.readInt(buffer);
|
||||
packet.setLayout(layoutIndex >= 0 && layoutIndex < InventoryLayout.VALUES.length ? InventoryLayout.VALUES[layoutIndex] : InventoryLayout.NONE);
|
||||
|
||||
int craftingLayoutIndex = VarInts.readInt(buffer);
|
||||
packet.setCraftingLayout(craftingLayoutIndex >= 0 && craftingLayoutIndex < InventoryLayout.VALUES.length ? InventoryLayout.VALUES[craftingLayoutIndex] : InventoryLayout.NONE);
|
||||
}
|
||||
};
|
||||
|
||||
private static final BedrockPacketSerializer<FilterTextPacket> FILTER_TEXT = new FilterTextSerializer_v422() {
|
||||
@Override
|
||||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, FilterTextPacket packet) {
|
||||
packet.setText(helper.readStringMaxLen(buffer, 513));
|
||||
packet.setFromServer(buffer.readBoolean());
|
||||
}
|
||||
};
|
||||
|
||||
private static final BedrockPacketSerializer<CommandRequestPacket> COMMAND_REQUEST_SERIALIZER = new CommandRequestSerializer_v567() {
|
||||
@Override
|
||||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, CommandRequestPacket packet) {
|
||||
packet.setCommand(helper.readStringMaxLen(buffer, 513));
|
||||
packet.setCommandOriginData(helper.readCommandOrigin(buffer));
|
||||
packet.setInternal(buffer.readBoolean());
|
||||
packet.setVersion(VarInts.readInt(buffer));
|
||||
}
|
||||
};
|
||||
|
||||
private static final BedrockPacketSerializer<TextPacket> TEXT_SERIALIZER_V554 = new TextSerializer_v554() {
|
||||
@Override
|
||||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, TextPacket packet) {
|
||||
TextPacket.Type type = TextPacket.Type.values()[buffer.readUnsignedByte()];
|
||||
packet.setType(type);
|
||||
packet.setNeedsTranslation(buffer.readBoolean());
|
||||
|
||||
if (type == TextPacket.Type.CHAT) {
|
||||
packet.setSourceName(helper.readString(buffer));
|
||||
//The client does not send more than 512 characters, and we do not need to decode other TextPacket.Type
|
||||
packet.setMessage(helper.readStringMaxLen(buffer, 513));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported TextType " + type);
|
||||
}
|
||||
|
||||
packet.setXuid(helper.readString(buffer));
|
||||
packet.setPlatformChatId(helper.readString(buffer));
|
||||
}
|
||||
};
|
||||
|
||||
private static final BedrockPacketSerializer<TextPacket> TEXT_SERIALIZER = new TextSerializer_v685() {
|
||||
@Override
|
||||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, TextPacket packet) {
|
||||
TextPacket.Type type = TextPacket.Type.values()[buffer.readUnsignedByte()];
|
||||
packet.setType(type);
|
||||
packet.setNeedsTranslation(buffer.readBoolean());
|
||||
|
||||
if (type == TextPacket.Type.CHAT) {
|
||||
packet.setSourceName(helper.readString(buffer));
|
||||
//The client does not send more than 512 characters, and we do not need to decode other TextPacket.Type
|
||||
packet.setMessage(helper.readStringMaxLen(buffer, 513));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported TextType " + type);
|
||||
}
|
||||
|
||||
packet.setXuid(helper.readString(buffer));
|
||||
packet.setPlatformChatId(helper.readString(buffer));
|
||||
packet.setFilteredMessage(helper.readString(buffer));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializer that does nothing when trying to deserialize BossEventPacket since it is not used from the client.
|
||||
*/
|
||||
|
@ -181,15 +271,6 @@ class CodecProcessor {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client for codec v291.
|
||||
*/
|
||||
private static final BedrockPacketSerializer<SetEntityMotionPacket> SET_ENTITY_MOTION_SERIALIZER_V291 = new SetEntityMotionSerializer_v291() {
|
||||
@Override
|
||||
public void deserialize(ByteBuf buffer, BedrockCodecHelper helper, SetEntityMotionPacket packet) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializer that does nothing when trying to deserialize SetEntityMotionPacket since it is not used from the client for codec v662.
|
||||
*/
|
||||
|
@ -251,6 +332,7 @@ class CodecProcessor {
|
|||
.updateSerializer(SettingsCommandPacket.class, IGNORED_SERIALIZER)
|
||||
.updateSerializer(AnvilDamagePacket.class, IGNORED_SERIALIZER)
|
||||
.updateSerializer(RefreshEntitlementsPacket.class, IGNORED_SERIALIZER)
|
||||
.updateSerializer(EmoteListPacket.class, IGNORED_SERIALIZER)
|
||||
// Illegal when serverbound due to Geyser specific setup
|
||||
.updateSerializer(InventoryContentPacket.class, INVENTORY_CONTENT_SERIALIZER)
|
||||
.updateSerializer(InventorySlotPacket.class, INVENTORY_SLOT_SERIALIZER)
|
||||
|
@ -273,10 +355,19 @@ class CodecProcessor {
|
|||
.updateSerializer(SimpleEventPacket.class, IGNORED_SERIALIZER)
|
||||
.updateSerializer(MultiplayerSettingsPacket.class, IGNORED_SERIALIZER);
|
||||
|
||||
|
||||
if (codec.getProtocolVersion() < 685) {
|
||||
// Ignored bidirectional packets
|
||||
codecBuilder.updateSerializer(TickSyncPacket.class, IGNORED_SERIALIZER);
|
||||
}
|
||||
codecBuilder.updateSerializer(FilterTextPacket.class, FILTER_TEXT);
|
||||
codecBuilder.updateSerializer(CommandRequestPacket.class, COMMAND_REQUEST_SERIALIZER);
|
||||
codecBuilder.updateSerializer(SetPlayerInventoryOptionsPacket.class, SET_PLAYER_INVENTORY_OPTIONS_SERIALIZER);
|
||||
if (codec.getProtocolVersion() >= 685) {
|
||||
codecBuilder.updateSerializer(TextPacket.class, TEXT_SERIALIZER);
|
||||
} else {
|
||||
codecBuilder.updateSerializer(TextPacket.class, TEXT_SERIALIZER_V554);
|
||||
}
|
||||
|
||||
return codecBuilder.build();
|
||||
}
|
||||
|
|
|
@ -39,13 +39,16 @@ import org.geysermc.geyser.session.GeyserSession;
|
|||
public class LoggingPacketHandler implements BedrockPacketHandler {
|
||||
protected final GeyserImpl geyser;
|
||||
protected final GeyserSession session;
|
||||
protected final PacketCooldownManager cooldownHandler;
|
||||
|
||||
LoggingPacketHandler(GeyserImpl geyser, GeyserSession session) {
|
||||
this.geyser = geyser;
|
||||
this.session = session;
|
||||
this.cooldownHandler = new PacketCooldownManager(session);
|
||||
}
|
||||
|
||||
PacketSignal defaultHandler(BedrockPacket packet) {
|
||||
this.cooldownHandler.handle(packet);
|
||||
geyser.getLogger().debug("Handled packet: " + packet.getClass().getSimpleName());
|
||||
return PacketSignal.HANDLED;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
package org.geysermc.geyser.network;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BlockPickRequestPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BookEditPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.CommandRequestPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EntityPickRequestPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.FilterTextPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LecternUpdatePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LoginPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ModalFormResponsePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.RequestNetworkSettingsPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackChunkRequestPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackClientResponsePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.TextPacket;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PacketCooldownManager {
|
||||
|
||||
private final GeyserSession session;
|
||||
private final Map<String, CooldownSettings> packetCooldownSettings = new Object2ObjectOpenHashMap<>();
|
||||
private final Map<String, CooldownTracker> activeCooldowns = new Object2ObjectOpenHashMap<>();
|
||||
|
||||
public PacketCooldownManager(GeyserSession session) {
|
||||
this.session = session;
|
||||
|
||||
setPacketCooldown(LoginPacket.class, -1, 2);
|
||||
setPacketCooldown(ResourcePackClientResponsePacket.class, -1, 4);
|
||||
setPacketCooldown(ResourcePackChunkRequestPacket.class, -1, 0);
|
||||
setPacketCooldown(RequestNetworkSettingsPacket.class, -1, 2);
|
||||
setPacketCooldown(TextPacket.class, 1000, 50);
|
||||
setPacketCooldown(CommandRequestPacket.class, 1000, 50);
|
||||
setPacketCooldown(ModalFormResponsePacket.class, 1000, 50);
|
||||
setPacketCooldown(BlockEntityDataPacket.class, 1000, 40);
|
||||
setPacketCooldown(SetLocalPlayerAsInitializedPacket.class, 1000, 40);
|
||||
setPacketCooldown(BlockPickRequestPacket.class, 1000, 40);
|
||||
setPacketCooldown(EntityPickRequestPacket.class, 1000, 40);
|
||||
setPacketCooldown(BookEditPacket.class, 1000, 40);
|
||||
setPacketCooldown(FilterTextPacket.class, 1000, 40);
|
||||
setPacketCooldown(LecternUpdatePacket.class, 1000, 10);
|
||||
}
|
||||
|
||||
public void setPacketCooldown(Class<? extends BedrockPacket> packetClass, int cooldownMillis, int maxCount) {
|
||||
packetCooldownSettings.put(packetClass.getSimpleName(), new CooldownSettings(cooldownMillis, maxCount));
|
||||
}
|
||||
|
||||
private boolean isCooldown(BedrockPacket packet) {
|
||||
String packetName = packet.getClass().getSimpleName();
|
||||
CooldownSettings settings = packetCooldownSettings.get(packetName);
|
||||
if (settings == null) return false;
|
||||
|
||||
CooldownTracker tracker = activeCooldowns.computeIfAbsent(packetName, k -> {
|
||||
CooldownTracker newTracker = new CooldownTracker();
|
||||
long cooldownMillis = settings.cooldownMillis();
|
||||
if (cooldownMillis == -1) {
|
||||
newTracker.setExpiryTime(-1);
|
||||
} else {
|
||||
newTracker.setExpiryTime(System.currentTimeMillis() + cooldownMillis);
|
||||
}
|
||||
return newTracker;
|
||||
});
|
||||
tracker.incrementCount();
|
||||
|
||||
if (tracker.getExpiryTime() != -1 && tracker.getExpiryTime() <= System.currentTimeMillis()) {
|
||||
activeCooldowns.remove(packetName);
|
||||
return false;
|
||||
}
|
||||
|
||||
return tracker.getCount() >= settings.maxCount();
|
||||
}
|
||||
|
||||
public void handle(BedrockPacket packet) {
|
||||
String packetName = packet.getClass().getSimpleName();
|
||||
if (!isCooldown(packet)) return;
|
||||
if (session.getGeyser().getConfig().isDebugMode()) {
|
||||
CooldownTracker tracker = activeCooldowns.get(packetName);
|
||||
String message = session.getSocketAddress().getAddress().toString() + " -> Attempted to send too many packets " + packetName + " count " + tracker.getCount();
|
||||
if (session.isLoggedIn()) {
|
||||
message += " by user " + session.bedrockUsername();
|
||||
}
|
||||
session.getGeyser().getLogger().debug(message);
|
||||
}
|
||||
session.disconnect("many Packets " + packetName);
|
||||
}
|
||||
|
||||
private record CooldownSettings(int cooldownMillis, int maxCount) {
|
||||
}
|
||||
|
||||
@Getter
|
||||
private class CooldownTracker {
|
||||
private long count;
|
||||
@Setter
|
||||
private long expiryTime;
|
||||
|
||||
public void incrementCount() {
|
||||
this.count++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,6 +37,7 @@ import org.cloudburstmc.protocol.bedrock.netty.codec.compression.CompressionStra
|
|||
import org.cloudburstmc.protocol.bedrock.netty.codec.compression.SimpleCompressionStrategy;
|
||||
import org.cloudburstmc.protocol.bedrock.netty.codec.compression.ZlibCompression;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LecternUpdatePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.LoginPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ModalFormResponsePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
|
||||
|
@ -73,15 +74,12 @@ import org.geysermc.geyser.util.VersionCheckUtils;
|
|||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
|
||||
private boolean networkSettingsRequested = false;
|
||||
private final Deque<String> packsToSent = new ArrayDeque<>();
|
||||
private final CompressionStrategy compressionStrategy;
|
||||
|
||||
private SessionLoadResourcePacksEventImpl resourcePackLoadEvent;
|
||||
|
@ -101,6 +99,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
@Override
|
||||
PacketSignal defaultHandler(BedrockPacket packet) {
|
||||
this.cooldownHandler.handle(packet);
|
||||
return translateAndDefault(packet);
|
||||
}
|
||||
|
||||
|
@ -150,6 +149,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
@Override
|
||||
public PacketSignal handle(RequestNetworkSettingsPacket packet) {
|
||||
this.cooldownHandler.handle(packet);
|
||||
if (!setCorrectCodec(packet.getProtocolVersion())) {
|
||||
return PacketSignal.HANDLED;
|
||||
}
|
||||
|
@ -169,6 +169,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
@Override
|
||||
public PacketSignal handle(LoginPacket loginPacket) {
|
||||
this.cooldownHandler.handle(loginPacket);
|
||||
if (geyser.isShuttingDown() || geyser.isReloading()) {
|
||||
// Don't allow new players in if we're no longer operating
|
||||
session.disconnect(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.kick.message"));
|
||||
|
@ -220,6 +221,11 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
@Override
|
||||
public PacketSignal handle(ResourcePackClientResponsePacket packet) {
|
||||
this.cooldownHandler.handle(packet);
|
||||
if (packet.getPackIds().size() > this.resourcePackLoadEvent.getPacks().size()) {
|
||||
session.disconnect("Packet " + packet.getClass().getSimpleName() + " PackIds max count");
|
||||
return PacketSignal.HANDLED;
|
||||
}
|
||||
switch (packet.getStatus()) {
|
||||
case COMPLETED:
|
||||
if (geyser.getConfig().getRemote().authType() != AuthType.ONLINE) {
|
||||
|
@ -232,8 +238,24 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
break;
|
||||
|
||||
case SEND_PACKS:
|
||||
packsToSent.addAll(packet.getPackIds());
|
||||
sendPackDataInfo(packsToSent.pop());
|
||||
int chunkIndex = 1;
|
||||
for (String id : packet.getPackIds()) {
|
||||
|
||||
String[] packID = id.split("_", 2);
|
||||
if (packID.length != 2) {
|
||||
session.disconnect("Invalid packID id: " + id);
|
||||
break;
|
||||
}
|
||||
ResourcePack pack = this.resourcePackLoadEvent.getPacks().get(packID[0]);
|
||||
if (pack == null) {
|
||||
session.disconnect("Invalid request unknown pack " + packID[0] + ", available packs: " + this.resourcePackLoadEvent.getPacks().keySet());
|
||||
break;
|
||||
}
|
||||
|
||||
sendPackDataInfo(id);
|
||||
chunkIndex += (int) ((this.resourcePackLoadEvent.getPacks().get(packID[0]).codec().size() + GeyserResourcePack.CHUNK_SIZE) / GeyserResourcePack.CHUNK_SIZE);
|
||||
}
|
||||
cooldownHandler.setPacketCooldown(ResourcePackChunkRequestPacket.class, -1, chunkIndex);
|
||||
break;
|
||||
|
||||
case HAVE_ALL_PACKS:
|
||||
|
@ -268,6 +290,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
@Override
|
||||
public PacketSignal handle(ModalFormResponsePacket packet) {
|
||||
this.cooldownHandler.handle(packet);
|
||||
session.executeInEventLoop(() -> session.getFormCache().handleResponse(packet));
|
||||
return PacketSignal.HANDLED;
|
||||
}
|
||||
|
@ -308,8 +331,13 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
@Override
|
||||
public PacketSignal handle(ResourcePackChunkRequestPacket packet) {
|
||||
this.cooldownHandler.handle(packet);
|
||||
ResourcePackChunkDataPacket data = new ResourcePackChunkDataPacket();
|
||||
ResourcePack pack = this.resourcePackLoadEvent.getPacks().get(packet.getPackId().toString());
|
||||
if (pack == null) {
|
||||
session.disconnect("Invalid request for chunk " + packet.getChunkIndex() + " of unknown pack " + packet.getPackId() + ", available packs: " + this.resourcePackLoadEvent.getPacks().keySet());
|
||||
return PacketSignal.HANDLED;
|
||||
}
|
||||
PackCodec codec = pack.codec();
|
||||
|
||||
data.setChunkIndex(packet.getChunkIndex());
|
||||
|
@ -318,6 +346,10 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
data.setPackId(packet.getPackId());
|
||||
|
||||
int offset = packet.getChunkIndex() * GeyserResourcePack.CHUNK_SIZE;
|
||||
if (offset < 0 || offset >= codec.size()) {
|
||||
session.disconnect("Invalid out-of-bounds request for chunk " + packet.getChunkIndex() + " of " + packet.getPackId() + " offset " + offset + ", file size " + codec.size());
|
||||
return PacketSignal.HANDLED;
|
||||
}
|
||||
long remainingSize = codec.size() - offset;
|
||||
byte[] packData = new byte[(int) MathUtils.constrain(remainingSize, 0, GeyserResourcePack.CHUNK_SIZE)];
|
||||
|
||||
|
@ -332,17 +364,12 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
session.sendUpstreamPacket(data);
|
||||
|
||||
// Check if it is the last chunk and send next pack in queue when available.
|
||||
if (remainingSize <= GeyserResourcePack.CHUNK_SIZE && !packsToSent.isEmpty()) {
|
||||
sendPackDataInfo(packsToSent.pop());
|
||||
}
|
||||
|
||||
return PacketSignal.HANDLED;
|
||||
}
|
||||
|
||||
private void sendPackDataInfo(String id) {
|
||||
ResourcePackDataInfoPacket data = new ResourcePackDataInfoPacket();
|
||||
String[] packID = id.split("_");
|
||||
String[] packID = id.split("_", 2);
|
||||
ResourcePack pack = this.resourcePackLoadEvent.getPacks().get(packID[0]);
|
||||
PackCodec codec = pack.codec();
|
||||
ResourcePackManifest.Header header = pack.manifest().header();
|
||||
|
|
|
@ -236,7 +236,7 @@ public final class GeyserServer {
|
|||
.group(group, childGroup)
|
||||
.option(RakChannelOption.RAK_HANDLE_PING, true)
|
||||
.option(RakChannelOption.RAK_MAX_MTU, this.geyser.getConfig().getMtu())
|
||||
.option(RakChannelOption.RAK_PACKET_LIMIT, rakPacketLimit)
|
||||
.option(RakChannelOption.RAK_PACKET_LIMIT, rakPacketLimit) // FIXME When using Velocity, the proxy server gets kicked for exceeding the limit, even if this value is increased tenfold. With an online count of 1000, this happens about 40 times a day at a value of 450. It is unclear why it detects the server's IP with Velocity, rather than the players' IPs.
|
||||
.option(RakChannelOption.RAK_GLOBAL_PACKET_LIMIT, rakGlobalPacketLimit)
|
||||
.option(RakChannelOption.RAK_SEND_COOKIE, rakSendCookie)
|
||||
.childHandler(serverInitializer);
|
||||
|
|
|
@ -118,7 +118,6 @@ import org.geysermc.geyser.api.network.AuthType;
|
|||
import org.geysermc.geyser.api.network.RemoteServer;
|
||||
import org.geysermc.geyser.api.util.PlatformType;
|
||||
import org.geysermc.geyser.command.GeyserCommandSource;
|
||||
import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption;
|
||||
import org.geysermc.geyser.configuration.GeyserConfiguration;
|
||||
import org.geysermc.geyser.entity.EntityDefinitions;
|
||||
import org.geysermc.geyser.entity.GeyserEntityData;
|
||||
|
@ -346,7 +345,9 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
// Exposed for GeyserConnect usage
|
||||
protected boolean sentSpawnPacket;
|
||||
|
||||
@Getter
|
||||
private boolean loggedIn;
|
||||
@Getter
|
||||
private boolean loggingIn;
|
||||
|
||||
@Setter
|
||||
|
@ -587,8 +588,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
@Setter
|
||||
private boolean waitingForStatistics = false;
|
||||
|
||||
private final Set<UUID> emotes;
|
||||
|
||||
/**
|
||||
* Whether advanced tooltips will be added to the player's items.
|
||||
*/
|
||||
|
@ -676,13 +675,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
this.spawned = false;
|
||||
this.loggedIn = false;
|
||||
|
||||
if (geyser.getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.NO_EMOTES) {
|
||||
this.emotes = new HashSet<>();
|
||||
geyser.getSessionManager().getSessions().values().forEach(player -> this.emotes.addAll(player.getEmotes()));
|
||||
} else {
|
||||
this.emotes = null;
|
||||
}
|
||||
|
||||
this.remoteServer = geyser.defaultRemoteServer();
|
||||
}
|
||||
|
||||
|
@ -1938,23 +1930,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
this.statistics.putAll(statistics);
|
||||
}
|
||||
|
||||
public void refreshEmotes(List<UUID> emotes) {
|
||||
this.emotes.addAll(emotes);
|
||||
for (GeyserSession player : geyser.getSessionManager().getSessions().values()) {
|
||||
List<UUID> pieces = new ArrayList<>();
|
||||
for (UUID piece : emotes) {
|
||||
if (!player.getEmotes().contains(piece)) {
|
||||
pieces.add(piece);
|
||||
}
|
||||
player.getEmotes().add(piece);
|
||||
}
|
||||
EmoteListPacket emoteList = new EmoteListPacket();
|
||||
emoteList.setRuntimeEntityId(player.getPlayerEntity().getGeyserId());
|
||||
emoteList.getPieceIds().addAll(pieces);
|
||||
player.sendUpstreamPacket(emoteList);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canUseCommandBlocks() {
|
||||
return instabuild && opPermissionLevel >= 2;
|
||||
}
|
||||
|
|
|
@ -25,18 +25,21 @@
|
|||
|
||||
package org.geysermc.geyser.session.cache;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ModalFormRequestPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ModalFormResponsePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.cloudburstmc.protocol.bedrock.data.ModalFormCancelReason;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ModalFormRequestPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ModalFormResponsePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.NetworkStackLatencyPacket;
|
||||
import org.geysermc.cumulus.form.Form;
|
||||
import org.geysermc.cumulus.form.SimpleForm;
|
||||
import org.geysermc.cumulus.form.impl.FormDefinitions;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
|
@ -52,11 +55,22 @@ public class FormCache {
|
|||
private final FormDefinitions formDefinitions = FormDefinitions.instance();
|
||||
private final AtomicInteger formIdCounter = new AtomicInteger(0);
|
||||
private final Int2ObjectMap<Form> forms = new Int2ObjectOpenHashMap<>();
|
||||
LinkedList<Integer> formsOrderList = new LinkedList<>();
|
||||
private final GeyserSession session;
|
||||
|
||||
public int addForm(Form form) {
|
||||
int formId = formIdCounter.getAndIncrement();
|
||||
forms.put(formId, form);
|
||||
formsOrderList.add(formId);
|
||||
|
||||
if (formsOrderList.size() > 50) {
|
||||
int removeFormId = formsOrderList.getFirst();
|
||||
ModalFormResponsePacket packet = new ModalFormResponsePacket();
|
||||
packet.setFormId(removeFormId);
|
||||
packet.setCancelReason(Optional.of(ModalFormCancelReason.USER_CLOSED));
|
||||
packet.setFormData(null);
|
||||
this.handleResponse(packet);
|
||||
}
|
||||
return formId;
|
||||
}
|
||||
|
||||
|
@ -96,6 +110,7 @@ public class FormCache {
|
|||
|
||||
public void handleResponse(ModalFormResponsePacket response) {
|
||||
Form form = forms.remove(response.getFormId());
|
||||
formsOrderList.remove((Integer) response.getFormId());
|
||||
if (form == null) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -39,8 +39,7 @@ public class BedrockCommandRequestTranslator extends PacketTranslator<CommandReq
|
|||
|
||||
@Override
|
||||
public void translate(GeyserSession session, CommandRequestPacket packet) {
|
||||
String command = MessageTranslator.convertToPlainText(packet.getCommand());
|
||||
handleCommand(session, MessageTranslator.normalizeSpace(command).substring(1));
|
||||
handleCommand(session, MessageTranslator.normalizeSpace(MessageTranslator.convertToPlainText(packet.getCommand())).substring(1));
|
||||
}
|
||||
|
||||
static void handleCommand(GeyserSession session, String command) {
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019-2022 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.translator.protocol.bedrock;
|
||||
|
||||
import org.cloudburstmc.protocol.bedrock.packet.EmoteListPacket;
|
||||
import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.translator.protocol.PacketTranslator;
|
||||
import org.geysermc.geyser.translator.protocol.Translator;
|
||||
|
||||
@Translator(packet = EmoteListPacket.class)
|
||||
public class BedrockEmoteListTranslator extends PacketTranslator<EmoteListPacket> {
|
||||
|
||||
@Override
|
||||
public void translate(GeyserSession session, EmoteListPacket packet) {
|
||||
if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) {
|
||||
return;
|
||||
}
|
||||
|
||||
session.refreshEmotes(packet.getPieceIds());
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue