mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
ResourcePack limit
This commit is contained in:
parent
383d16d49b
commit
644cbb05f8
2 changed files with 69 additions and 51 deletions
|
|
@ -9,30 +9,37 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
|
||||
public class PacketCooldownManager {
|
||||
private static final Map<String, CooldownSettings> PACKET_COOLDOWN_SETTINGS = new HashMap<>();
|
||||
|
||||
static {
|
||||
setPacketCooldown(LoginPacket.class, -1, 2);
|
||||
setPacketCooldown(TextPacket.class, 1000, 10);
|
||||
setPacketCooldown(CommandRequestPacket.class, 1000, 10);
|
||||
setPacketCooldown(ModalFormResponsePacket.class, 1000, 10);
|
||||
}
|
||||
private final Map<String, CooldownSettings> packetCooldownSettings = new HashMap<>();
|
||||
|
||||
private final GeyserSession session;
|
||||
@Setter
|
||||
private long cooldownMillisDebug;
|
||||
private long expiryTimeMillisDebug;
|
||||
|
||||
public static void setPacketCooldown(Class<? extends BedrockPacket> packetClass, int cooldownMillis, int maxCount) {
|
||||
PACKET_COOLDOWN_SETTINGS.put(packetClass.getSimpleName(), new CooldownSettings(cooldownMillis, maxCount));
|
||||
public PacketCooldownManager(GeyserSession session, long cooldownMillisDebug) {
|
||||
this.session = session;
|
||||
this.setCooldownMillisDebug(cooldownMillisDebug);
|
||||
this.expiryTimeMillisDebug = 0;
|
||||
|
||||
setPacketCooldown(LoginPacket.class, -1, 2);
|
||||
setPacketCooldown(ResourcePackClientResponsePacket.class, -1, 4);
|
||||
setPacketCooldown(ResourcePackChunkRequestPacket.class, -1, 0);
|
||||
setPacketCooldown(TextPacket.class, 1000, 10);
|
||||
setPacketCooldown(CommandRequestPacket.class, 1000, 10);
|
||||
setPacketCooldown(ModalFormResponsePacket.class, 1000, 10);
|
||||
}
|
||||
|
||||
public void setPacketCooldown(Class<? extends BedrockPacket> packetClass, int cooldownMillis, int maxCount) {
|
||||
packetCooldownSettings.put(packetClass.getSimpleName(), new CooldownSettings(cooldownMillis, maxCount));
|
||||
}
|
||||
|
||||
private final Map<String, CooldownTracker> activeCooldowns = new HashMap<>();
|
||||
|
||||
private boolean isCooldownActive(String packetName) {
|
||||
private boolean isCooldownActive(BedrockPacket packet) {
|
||||
String packetName = packet.getClass().getSimpleName();
|
||||
CooldownTracker tracker = activeCooldowns.get(packetName);
|
||||
if (tracker != null && tracker.getCount() >= PACKET_COOLDOWN_SETTINGS.get(packetName).maxCount()) {
|
||||
if (tracker.getExpiryTime() <= System.currentTimeMillis()) {
|
||||
if (tracker != null && tracker.getCount() >= packetCooldownSettings.get(packetName).maxCount()) {
|
||||
if (tracker.getExpiryTime() != -1 && tracker.getExpiryTime() <= System.currentTimeMillis()) {
|
||||
activeCooldowns.remove(packetName);
|
||||
} else {
|
||||
return true;
|
||||
|
|
@ -41,22 +48,27 @@ public class PacketCooldownManager {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void updateCooldown(String packetName, long cooldownMillis) {
|
||||
private void updateCooldown(BedrockPacket packet) {
|
||||
String packetName = packet.getClass().getSimpleName();
|
||||
CooldownSettings settings = packetCooldownSettings.get(packetName);
|
||||
activeCooldowns.computeIfAbsent(packetName, k -> new CooldownTracker());
|
||||
CooldownTracker tracker = activeCooldowns.get(packetName);
|
||||
tracker.incrementCount();
|
||||
tracker.setExpiryTime(System.currentTimeMillis() + cooldownMillis);
|
||||
if (settings.cooldownMillis() == -1) {
|
||||
tracker.setExpiryTime(settings.cooldownMillis());
|
||||
} else {
|
||||
tracker.setExpiryTime(System.currentTimeMillis() + settings.cooldownMillis());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean handle(BedrockPacket packet) {
|
||||
String packetName = packet.getClass().getSimpleName();
|
||||
if (PACKET_COOLDOWN_SETTINGS.containsKey(packetName)) {
|
||||
CooldownSettings settings = PACKET_COOLDOWN_SETTINGS.get(packetName);
|
||||
updateCooldown(packetName, settings.cooldownMillis());
|
||||
if (isCooldownActive(packetName)) {
|
||||
if (packetCooldownSettings.containsKey(packetName)) {
|
||||
updateCooldown(packet);
|
||||
if (isCooldownActive(packet)) {
|
||||
if (expiryTimeMillisDebug <= System.currentTimeMillis()) {
|
||||
CooldownTracker tracker = activeCooldowns.get(packetName);
|
||||
String message = session.getSocketAddress().getAddress().toString() + " -> Attempted to send too many packets " + packet.getClass().getSimpleName() + "count " + tracker.getCount();
|
||||
String message = session.getSocketAddress().getAddress().toString() + " -> Attempted to send too many packets " + packet.getClass().getSimpleName() + " count " + tracker.getCount();
|
||||
if (session.isLoggedIn()) {
|
||||
message += " by user " + session.bedrockUsername();
|
||||
}
|
||||
|
|
@ -69,16 +81,9 @@ public class PacketCooldownManager {
|
|||
return true;
|
||||
}
|
||||
|
||||
public PacketCooldownManager(GeyserSession session, long cooldownMillisDebug) {
|
||||
this.session = session;
|
||||
this.setCooldownMillisDebug(cooldownMillisDebug);
|
||||
this.expiryTimeMillisDebug = 0;
|
||||
}
|
||||
|
||||
private record CooldownSettings(int cooldownMillis, int maxCount) {
|
||||
}
|
||||
|
||||
|
||||
@Getter
|
||||
private class CooldownTracker {
|
||||
private long count;
|
||||
|
|
|
|||
|
|
@ -36,20 +36,7 @@ import org.cloudburstmc.protocol.bedrock.data.ResourcePackType;
|
|||
import org.cloudburstmc.protocol.bedrock.netty.codec.compression.CompressionStrategy;
|
||||
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.LoginPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ModalFormResponsePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.NetworkSettingsPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.RequestNetworkSettingsPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackChunkDataPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackChunkRequestPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackClientResponsePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackDataInfoPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackStackPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.ResourcePacksInfoPacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket;
|
||||
import org.cloudburstmc.protocol.bedrock.packet.*;
|
||||
import org.cloudburstmc.protocol.common.PacketSignal;
|
||||
import org.cloudburstmc.protocol.common.util.Zlib;
|
||||
import org.geysermc.geyser.Constants;
|
||||
|
|
@ -73,15 +60,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;
|
||||
|
|
@ -226,6 +210,13 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
@Override
|
||||
public PacketSignal handle(ResourcePackClientResponsePacket packet) {
|
||||
if (this.handleLimit(packet)) {
|
||||
return PacketSignal.HANDLED;
|
||||
}
|
||||
if (packet.getPackIds().size() > this.resourcePackLoadEvent.getPacks().size()) {
|
||||
session.disconnect("Packet " + packet.getClass().getName() + " PackIds max count");
|
||||
return PacketSignal.HANDLED;
|
||||
}
|
||||
switch (packet.getStatus()) {
|
||||
case COMPLETED:
|
||||
if (geyser.getConfig().getRemote().authType() != AuthType.ONLINE) {
|
||||
|
|
@ -238,8 +229,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:
|
||||
|
|
@ -317,8 +324,15 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||
|
||||
@Override
|
||||
public PacketSignal handle(ResourcePackChunkRequestPacket packet) {
|
||||
if (this.handleLimit(packet)) {
|
||||
return PacketSignal.HANDLED;
|
||||
}
|
||||
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());
|
||||
|
|
@ -327,6 +341,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)];
|
||||
|
||||
|
|
@ -341,11 +359,6 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue