Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-19 22:40:18 +01:00
Initial stab at implementing 1.20.30's new CDN feature for resource packs
Dieser Commit ist enthalten in:
Ursprung
e8048ede08
Commit
68516a8b0b
@ -29,6 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||||
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
|
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
|
||||||
import org.geysermc.geyser.api.pack.ResourcePack;
|
import org.geysermc.geyser.api.pack.ResourcePack;
|
||||||
|
import org.geysermc.geyser.api.pack.ResourcePackCDNEntry;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -48,6 +49,13 @@ public abstract class SessionLoadResourcePacksEvent extends ConnectionEvent {
|
|||||||
*/
|
*/
|
||||||
public abstract @NonNull List<ResourcePack> resourcePacks();
|
public abstract @NonNull List<ResourcePack> resourcePacks();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an unmodifiable list of {@link ResourcePackCDNEntry}s that will be sent to the client.
|
||||||
|
*
|
||||||
|
* @return an unmodifiable list of resource pack CDN entries that will be sent to the client.
|
||||||
|
*/
|
||||||
|
public abstract @NonNull List<ResourcePackCDNEntry> cdnEntries();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a {@link ResourcePack} to be sent to the client.
|
* Registers a {@link ResourcePack} to be sent to the client.
|
||||||
*
|
*
|
||||||
@ -58,7 +66,14 @@ public abstract class SessionLoadResourcePacksEvent extends ConnectionEvent {
|
|||||||
public abstract boolean register(@NonNull ResourcePack resourcePack);
|
public abstract boolean register(@NonNull ResourcePack resourcePack);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unregisters a resource pack from being sent to the client.
|
* Registers a {@link ResourcePackCDNEntry} to be sent to the client.
|
||||||
|
*
|
||||||
|
* @param entry a resource pack CDN entry that will be sent to the client.
|
||||||
|
*/
|
||||||
|
public abstract boolean register(@NonNull ResourcePackCDNEntry entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters a {@link ResourcePack} or {@link ResourcePackCDNEntry} from being sent to the client.
|
||||||
*
|
*
|
||||||
* @param uuid the UUID of the resource pack
|
* @param uuid the UUID of the resource pack
|
||||||
* @return true whether the resource pack was removed from the list of resource packs.
|
* @return true whether the resource pack was removed from the list of resource packs.
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019-2023 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.api.pack;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public record ResourcePackCDNEntry(
|
||||||
|
String url,
|
||||||
|
UUID uuid
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
@ -30,6 +30,7 @@ import org.geysermc.geyser.GeyserLogger;
|
|||||||
import org.geysermc.geyser.api.network.AuthType;
|
import org.geysermc.geyser.api.network.AuthType;
|
||||||
import org.geysermc.geyser.api.network.BedrockListener;
|
import org.geysermc.geyser.api.network.BedrockListener;
|
||||||
import org.geysermc.geyser.api.network.RemoteServer;
|
import org.geysermc.geyser.api.network.RemoteServer;
|
||||||
|
import org.geysermc.geyser.api.pack.ResourcePackCDNEntry;
|
||||||
import org.geysermc.geyser.network.CIDRMatcher;
|
import org.geysermc.geyser.network.CIDRMatcher;
|
||||||
import org.geysermc.geyser.network.GameProtocol;
|
import org.geysermc.geyser.network.GameProtocol;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
@ -96,6 +97,8 @@ public interface GeyserConfiguration {
|
|||||||
|
|
||||||
boolean isForceResourcePacks();
|
boolean isForceResourcePacks();
|
||||||
|
|
||||||
|
List<ResourcePackCDNEntry> getCDNResourcePacks();
|
||||||
|
|
||||||
boolean isXboxAchievementsEnabled();
|
boolean isXboxAchievementsEnabled();
|
||||||
|
|
||||||
int getCacheImages();
|
int getCacheImages();
|
||||||
|
@ -36,15 +36,14 @@ import lombok.Getter;
|
|||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.api.network.AuthType;
|
import org.geysermc.geyser.api.network.AuthType;
|
||||||
|
import org.geysermc.geyser.api.pack.ResourcePackCDNEntry;
|
||||||
import org.geysermc.geyser.network.CIDRMatcher;
|
import org.geysermc.geyser.network.CIDRMatcher;
|
||||||
import org.geysermc.geyser.text.AsteriskSerializer;
|
import org.geysermc.geyser.text.AsteriskSerializer;
|
||||||
import org.geysermc.geyser.text.GeyserLocale;
|
import org.geysermc.geyser.text.GeyserLocale;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collections;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@ -136,6 +135,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
|||||||
@JsonProperty("force-resource-packs")
|
@JsonProperty("force-resource-packs")
|
||||||
private boolean forceResourcePacks = true;
|
private boolean forceResourcePacks = true;
|
||||||
|
|
||||||
|
@JsonProperty("cdn-resource-packs")
|
||||||
|
private Map<UUID, String> cdnResourcePacks = new HashMap<>();
|
||||||
|
|
||||||
@JsonProperty("xbox-achievements-enabled")
|
@JsonProperty("xbox-achievements-enabled")
|
||||||
private boolean xboxAchievementsEnabled = false;
|
private boolean xboxAchievementsEnabled = false;
|
||||||
|
|
||||||
@ -343,4 +345,13 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
|
|||||||
return AuthType.getByName(p.getValueAsString());
|
return AuthType.getByName(p.getValueAsString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ResourcePackCDNEntry> getCDNResourcePacks() {
|
||||||
|
List<ResourcePackCDNEntry> entries = new ArrayList<>();
|
||||||
|
for (Map.Entry<UUID, String> entry : cdnResourcePacks.entrySet()) {
|
||||||
|
entries.add(new ResourcePackCDNEntry(entry.getValue(), entry.getKey()));
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ package org.geysermc.geyser.event.type;
|
|||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.geysermc.geyser.api.event.bedrock.SessionLoadResourcePacksEvent;
|
import org.geysermc.geyser.api.event.bedrock.SessionLoadResourcePacksEvent;
|
||||||
import org.geysermc.geyser.api.pack.ResourcePack;
|
import org.geysermc.geyser.api.pack.ResourcePack;
|
||||||
|
import org.geysermc.geyser.api.pack.ResourcePackCDNEntry;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -38,9 +39,12 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE
|
|||||||
|
|
||||||
private final Map<String, ResourcePack> packs;
|
private final Map<String, ResourcePack> packs;
|
||||||
|
|
||||||
public SessionLoadResourcePacksEventImpl(GeyserSession session, Map<String, ResourcePack> packMap) {
|
private final List<ResourcePackCDNEntry> cdnEntries;
|
||||||
|
|
||||||
|
public SessionLoadResourcePacksEventImpl(GeyserSession session, Map<String, ResourcePack> packMap, List<ResourcePackCDNEntry> cdnEntries) {
|
||||||
super(session);
|
super(session);
|
||||||
this.packs = packMap;
|
this.packs = packMap;
|
||||||
|
this.cdnEntries = cdnEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull Map<String, ResourcePack> getPacks() {
|
public @NonNull Map<String, ResourcePack> getPacks() {
|
||||||
@ -52,18 +56,41 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE
|
|||||||
return List.copyOf(packs.values());
|
return List.copyOf(packs.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NonNull List<ResourcePackCDNEntry> cdnEntries() {
|
||||||
|
return List.copyOf(cdnEntries);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean register(@NonNull ResourcePack resourcePack) {
|
public boolean register(@NonNull ResourcePack resourcePack) {
|
||||||
String packID = resourcePack.manifest().header().uuid().toString();
|
String packID = resourcePack.manifest().header().uuid().toString();
|
||||||
if (packs.containsValue(resourcePack) || packs.containsKey(packID)) {
|
if (packs.containsValue(resourcePack) || packs.containsKey(packID)
|
||||||
|
|| !cdnEntries.isEmpty() && cdnEntries.stream().anyMatch(entry -> entry.uuid().toString().equals(packID))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
packs.put(resourcePack.manifest().header().uuid().toString(), resourcePack);
|
packs.put(resourcePack.manifest().header().uuid().toString(), resourcePack);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean register(@NonNull ResourcePackCDNEntry entry) {
|
||||||
|
UUID packID = entry.uuid();
|
||||||
|
if (packs.containsKey(packID.toString()) || cdnEntries.contains(entry)
|
||||||
|
|| !cdnEntries.isEmpty() && cdnEntries.stream().anyMatch(cdnEntry -> cdnEntry.uuid().equals(packID))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cdnEntries.add(entry);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean unregister(@NonNull UUID uuid) {
|
public boolean unregister(@NonNull UUID uuid) {
|
||||||
return packs.remove(uuid.toString()) != null;
|
if (packs.containsKey(uuid.toString())) {
|
||||||
|
return packs.remove(uuid.toString()) != null;
|
||||||
|
} else if (!cdnEntries.isEmpty() && cdnEntries.stream().anyMatch(entry -> entry.uuid().equals(uuid))) {
|
||||||
|
return cdnEntries.removeIf(entry -> entry.uuid().equals(uuid));
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,10 @@ public final class GameProtocol {
|
|||||||
return session.getUpstream().getProtocolVersion() < Bedrock_v594.CODEC.getProtocolVersion();
|
return session.getUpstream().getProtocolVersion() < Bedrock_v594.CODEC.getProtocolVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isPre1_20_30(GeyserSession session) {
|
||||||
|
return session.getUpstream().getProtocolVersion() < Bedrock_v618.CODEC.getProtocolVersion();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the {@link PacketCodec} for Minecraft: Java Edition.
|
* Gets the {@link PacketCodec} for Minecraft: Java Edition.
|
||||||
*
|
*
|
||||||
|
@ -31,26 +31,14 @@ import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec;
|
|||||||
import org.cloudburstmc.protocol.bedrock.data.ExperimentData;
|
import org.cloudburstmc.protocol.bedrock.data.ExperimentData;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm;
|
import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm;
|
||||||
import org.cloudburstmc.protocol.bedrock.data.ResourcePackType;
|
import org.cloudburstmc.protocol.bedrock.data.ResourcePackType;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.*;
|
||||||
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.common.PacketSignal;
|
import org.cloudburstmc.protocol.common.PacketSignal;
|
||||||
import org.geysermc.geyser.Constants;
|
import org.geysermc.geyser.Constants;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.api.network.AuthType;
|
import org.geysermc.geyser.api.network.AuthType;
|
||||||
import org.geysermc.geyser.api.pack.PackCodec;
|
import org.geysermc.geyser.api.pack.PackCodec;
|
||||||
import org.geysermc.geyser.api.pack.ResourcePack;
|
import org.geysermc.geyser.api.pack.ResourcePack;
|
||||||
|
import org.geysermc.geyser.api.pack.ResourcePackCDNEntry;
|
||||||
import org.geysermc.geyser.api.pack.ResourcePackManifest;
|
import org.geysermc.geyser.api.pack.ResourcePackManifest;
|
||||||
import org.geysermc.geyser.event.type.SessionLoadResourcePacksEventImpl;
|
import org.geysermc.geyser.event.type.SessionLoadResourcePacksEventImpl;
|
||||||
import org.geysermc.geyser.pack.GeyserResourcePack;
|
import org.geysermc.geyser.pack.GeyserResourcePack;
|
||||||
@ -178,7 +166,8 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||||||
|
|
||||||
geyser.getSessionManager().addPendingSession(session);
|
geyser.getSessionManager().addPendingSession(session);
|
||||||
|
|
||||||
this.resourcePackLoadEvent = new SessionLoadResourcePacksEventImpl(session, new HashMap<>(Registries.RESOURCE_PACKS.get()));
|
GeyserImpl.getInstance().getLogger().error(geyser.getConfig().getCDNResourcePacks().toString());
|
||||||
|
this.resourcePackLoadEvent = new SessionLoadResourcePacksEventImpl(session, new HashMap<>(Registries.RESOURCE_PACKS.get()), geyser.getConfig().getCDNResourcePacks());
|
||||||
this.geyser.eventBus().fire(this.resourcePackLoadEvent);
|
this.geyser.eventBus().fire(this.resourcePackLoadEvent);
|
||||||
|
|
||||||
ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket();
|
ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket();
|
||||||
@ -189,6 +178,14 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
|||||||
header.uuid().toString(), header.version().toString(), codec.size(), pack.contentKey(),
|
header.uuid().toString(), header.version().toString(), codec.size(), pack.contentKey(),
|
||||||
"", header.uuid().toString(), false, false));
|
"", header.uuid().toString(), false, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add CDN entries if the client supports it
|
||||||
|
if (!GameProtocol.isPre1_20_30(session)) {
|
||||||
|
for (ResourcePackCDNEntry entry : this.resourcePackLoadEvent.cdnEntries()) {
|
||||||
|
GeyserImpl.getInstance().getLogger().error("Adding CDN entry: " + entry.url() + " for " + entry.uuid());
|
||||||
|
resourcePacksInfo.getCDNEntries().add(new ResourcePacksInfoPacket.CDNEntry(entry.uuid().toString(), entry.url()));
|
||||||
|
}
|
||||||
|
}
|
||||||
resourcePacksInfo.setForcedToAccept(GeyserImpl.getInstance().getConfig().isForceResourcePacks());
|
resourcePacksInfo.setForcedToAccept(GeyserImpl.getInstance().getConfig().isForceResourcePacks());
|
||||||
session.sendUpstreamPacket(resourcePacksInfo);
|
session.sendUpstreamPacket(resourcePacksInfo);
|
||||||
|
|
||||||
|
@ -175,6 +175,15 @@ above-bedrock-nether-building: false
|
|||||||
# want to download the resource packs.
|
# want to download the resource packs.
|
||||||
force-resource-packs: true
|
force-resource-packs: true
|
||||||
|
|
||||||
|
# A list of links to send to the client to download resource packs from.
|
||||||
|
# These must be direct links, and you need to include the resource pack uuid
|
||||||
|
# You can find the uuid in the manifest.json file inside the resource pack zip.
|
||||||
|
cdn-resource-packs:
|
||||||
|
# Example: GeyserOptionalPack
|
||||||
|
{
|
||||||
|
e5f5c938-a701-11eb-b2a3-047d7bb283ba : "https://ci.opencollab.dev/job/GeyserMC/job/GeyserOptionalPack/job/master/lastSuccessfulBuild/artifact/GeyserOptionalPack.mcpack"
|
||||||
|
}
|
||||||
|
|
||||||
# Allows Xbox achievements to be unlocked.
|
# Allows Xbox achievements to be unlocked.
|
||||||
# THIS DISABLES ALL COMMANDS FROM SUCCESSFULLY RUNNING FOR BEDROCK IN-GAME, as otherwise Bedrock thinks you are cheating.
|
# THIS DISABLES ALL COMMANDS FROM SUCCESSFULLY RUNNING FOR BEDROCK IN-GAME, as otherwise Bedrock thinks you are cheating.
|
||||||
xbox-achievements-enabled: false
|
xbox-achievements-enabled: false
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren