Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement sending CDN entries to Bedrock clients to download resource packs from #4205

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
68516a8
Initial stab at implementing 1.20.30's new CDN feature for resource p…
onebeastchris Oct 10, 2023
02d6473
Small tweaks: record formatting/javadocs
onebeastchris Oct 10, 2023
dbfc153
- Don't require configuring the packId, just the link instead
onebeastchris Oct 10, 2023
f74d36a
Remove forRemoval
onebeastchris Oct 10, 2023
94f2ea9
Rename cdn-resource-packs to resource-pack-urls, fix test, remove dup…
onebeastchris Oct 10, 2023
fd69b0c
Rename CDN entry list
onebeastchris Oct 10, 2023
c0227d3
Move loading cdn entries to separate function
onebeastchris Oct 11, 2023
b9c5bdd
Remove CDNEntry; those do not work as expected.
onebeastchris Oct 17, 2023
27c1562
remove outdated javadocs
onebeastchris Oct 17, 2023
5d06edd
Fallback system - download the pack to serve the client in case cdn f…
onebeastchris Oct 18, 2023
880de2d
Ensure GeyserUrlPackCodec.create returns a ResourcePack with the URL …
onebeastchris Oct 18, 2023
76a62ab
Check downloaded resource packs, yeet cdn naming scheme
onebeastchris Oct 18, 2023
3670914
start on proper url checking (application type/size)
onebeastchris Oct 24, 2023
498a415
Change fallback system
onebeastchris Nov 9, 2023
0004f5b
Testing: Don't require `application/zip` or `size` or weird zip forma…
onebeastchris Nov 9, 2023
cdd2aba
Merge remote-tracking branch 'upstream/master' into rp
onebeastchris Nov 9, 2023
15b8b93
We need to ensure no invalid packs end up being loaded - otherwise, c…
onebeastchris Nov 9, 2023
d4f0d8a
Re-add debug: Apparently, not just `application/zip` works....???
onebeastchris Nov 10, 2023
0ac91eb
Merge remote-tracking branch 'upstream/master' into rp
onebeastchris Dec 21, 2023
626189f
remove debug, ensure we fully check failed packs, merge master
onebeastchris Dec 21, 2023
f121299
More robust downloading/caching
onebeastchris Dec 22, 2023
303327a
oops
onebeastchris Dec 22, 2023
d2622a4
Add a registerAll method to register a collection of resource packs e…
onebeastchris Jan 15, 2024
4d99250
Merge remote-tracking branch 'upstream/master' into rp
onebeastchris Jan 25, 2024
2e776c4
Allow null content key
onebeastchris Jan 26, 2024
a4fa2e6
Merge remote-tracking branch 'upstream/master' into rp
onebeastchris Feb 16, 2024
b8fa18a
start: don't try to delete broken packs while we are still delivering…
onebeastchris Feb 19, 2024
c6511a0
update to "new" pack requirements
onebeastchris Feb 22, 2024
507a79e
Merge remote-tracking branch 'refs/remotes/upstream/master' into rp
onebeastchris Jun 19, 2024
86f6458
Code cleanup, less futures, more exceptions when needed
onebeastchris Jun 19, 2024
6053b7d
Yeet unused, update optionalpack link
onebeastchris Jun 19, 2024
2683b59
Minor cleanup
onebeastchris Jun 20, 2024
ba78dba
Add url codec creation method with no content key, remove boolean ret…
onebeastchris Jun 20, 2024
f56c182
Merge branch 'master' into rp
onebeastchris Jun 20, 2024
de54a5b
Ensure packs actually load
onebeastchris Jun 20, 2024
86f1389
Merge remote-tracking branch 'origin/rp' into rp
onebeastchris Jun 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.geysermc.geyser.api.connection.GeyserConnection;
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
import org.geysermc.geyser.api.pack.ResourcePack;
import org.geysermc.geyser.api.pack.ResourcePackCDNEntry;

import java.util.List;
import java.util.UUID;
Expand All @@ -48,6 +49,13 @@ public SessionLoadResourcePacksEvent(@NonNull GeyserConnection connection) {
*/
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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its not like we have a formal style guide, but if the javadoc body is the same as the @return tag, can we just have the return tag only?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, but this has been accepted before & i'd rather keep it consistent (or change all instances of that in api)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RFC :P

and it exists elsewhere afaik


/**
* Registers a {@link ResourcePack} to be sent to the client.
*
Expand All @@ -58,10 +66,17 @@ public SessionLoadResourcePacksEvent(@NonNull GeyserConnection connection) {
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 CDN entry that will be sent to the client to download a resource pack from.
*/
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
* @return true whether the resource pack was removed from the list of resource packs.
* @param uuid the UUID of the resource pack/CDN entry to remove.
* @return true whether the resource pack/CDN entry was removed successfully.
*/
public abstract boolean unregister(@NonNull UUID uuid);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* 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.event.lifecycle;

import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.event.Event;
import org.geysermc.geyser.api.pack.ResourcePack;
import org.geysermc.geyser.api.pack.ResourcePackCDNEntry;

import java.util.List;
import java.util.UUID;

/**
* Called when {@link ResourcePack}'s and {@link ResourcePackCDNEntry}'s are loaded within Geyser.
*
*/
public abstract class GeyserDefineResourcePacksEvent implements Event {
onebeastchris marked this conversation as resolved.
Show resolved Hide resolved

/**
* Gets an unmodifiable list of {@link ResourcePack}s that will be sent to clients.
*
* @return an unmodifiable list of resource packs that will be sent to clients.
*/
public abstract @NonNull List<ResourcePack> resourcePacks();

/**
* Gets an unmodifiable list of {@link ResourcePackCDNEntry}s that will be sent to clients.
*
* @return an unmodifiable list of resource pack CDN entries that will be sent to clients.
*/
public abstract @NonNull List<ResourcePackCDNEntry> cdnEntries();

/**
* Registers a {@link ResourcePack} to be sent to clients.
*
* @param resourcePack a resource pack that will be sent to clients.
* @return true if the resource pack was added successfully,
* or false if already present
*/
public abstract boolean register(@NonNull ResourcePack resourcePack);

/**
* Registers a {@link ResourcePackCDNEntry} to be sent to clients.
*
* @param entry CDN entry that will be sent to the client to download a resource pack from.
*/
public abstract boolean register(@NonNull ResourcePackCDNEntry entry);

/**
* Unregisters a {@link ResourcePack} or {@link ResourcePackCDNEntry} from being sent to clients.
*
* @param uuid the UUID of the resource pack/CDN entry to remove.
* @return true whether the resource pack/CDN entry was removed successfully.
*/
public abstract boolean unregister(@NonNull UUID uuid);
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@

/**
* Called when resource packs are loaded within Geyser.
* @deprecated Use {@link GeyserDefineResourcePacksEvent} instead.
*
* @param resourcePacks a mutable list of the currently listed resource packs
*/
public record GeyserLoadResourcePacksEvent(@NonNull List<Path> resourcePacks) implements Event {

@Deprecated
public record GeyserLoadResourcePacksEvent(@Deprecated @NonNull List<Path> resourcePacks) implements Event {
onebeastchris marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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;

/**
* Represents a CDN entry for a resource pack.
* The URL must be a direct download link to a Bedrock edition resource pack.
* The UUID must be the UUID of the resource pack.
*
* @param url URL from which the pack should be downloaded
* @param uuid UUID of the pack
*/
public record ResourcePackCDNEntry(String url, UUID uuid) {
}

Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ public interface GeyserConfiguration {

boolean isForceResourcePacks();

List<String> getCdnResourcePacks();

boolean isXboxAchievementsEnabled();

int getCacheImages();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@

import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
Expand Down Expand Up @@ -136,6 +137,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
@JsonProperty("force-resource-packs")
private boolean forceResourcePacks = true;

@JsonProperty("cdn-resource-packs")
private List<String> cdnResourcePacks = new ArrayList<>();

@JsonProperty("xbox-achievements-enabled")
private boolean xboxAchievementsEnabled = false;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* 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.event.type;

import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.event.lifecycle.GeyserDefineResourcePacksEvent;
import org.geysermc.geyser.api.pack.ResourcePack;
import org.geysermc.geyser.api.pack.ResourcePackCDNEntry;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public class GeyserDefineResourcePacksEventImpl extends GeyserDefineResourcePacksEvent {

private final Map<String, ResourcePack> packs;
private final Map<String, ResourcePackCDNEntry> cdnEntries;

public GeyserDefineResourcePacksEventImpl(Map<String, ResourcePack> packMap, List<ResourcePackCDNEntry> cdnEntries) {
this.packs = packMap;
this.cdnEntries = new HashMap<>();
cdnEntries.forEach(entry -> this.cdnEntries.put(entry.uuid().toString(), entry));
}

public @NonNull Map<String, ResourcePack> getPacks() {
return packs;
}

@Override
public @NonNull List<ResourcePack> resourcePacks() {
return List.copyOf(packs.values());
}

@Override
public @NonNull List<ResourcePackCDNEntry> cdnEntries() {
return List.copyOf(cdnEntries.values());
}

@Override
public boolean register(@NonNull ResourcePack resourcePack) {
String packID = resourcePack.manifest().header().uuid().toString();
if (packs.containsValue(resourcePack) || packs.containsKey(packID) || cdnEntries.containsKey(packID)) {
return false;
}
packs.put(resourcePack.manifest().header().uuid().toString(), resourcePack);
return true;
}

@Override
public boolean register(@NonNull ResourcePackCDNEntry entry) {
String packID = entry.uuid().toString();
if (packs.containsKey(packID) || cdnEntries.containsValue(entry) || cdnEntries.containsKey(packID)) {
return false;
}
cdnEntries.put(packID, entry);
return true;
}

@Override
public boolean unregister(@NonNull UUID uuid) {
if (packs.containsKey(uuid.toString())) {
return packs.remove(uuid.toString()) != null;
} else if (cdnEntries.containsKey(uuid.toString())) {
return cdnEntries.remove(uuid.toString()) != null;
} else {
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,24 @@
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.event.bedrock.SessionLoadResourcePacksEvent;
import org.geysermc.geyser.api.pack.ResourcePack;
import org.geysermc.geyser.api.pack.ResourcePackCDNEntry;
import org.geysermc.geyser.session.GeyserSession;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksEvent {

private final Map<String, ResourcePack> packs;
private final Map<String, ResourcePackCDNEntry> cdnEntries;

public SessionLoadResourcePacksEventImpl(GeyserSession session, Map<String, ResourcePack> packMap) {
public SessionLoadResourcePacksEventImpl(GeyserSession session, Map<String, ResourcePack> packMap, List<ResourcePackCDNEntry> cdnEntries) {
super(session);
this.packs = packMap;
this.cdnEntries = new HashMap<>();
cdnEntries.forEach(entry -> this.cdnEntries.put(entry.uuid().toString(), entry));
}

public @NonNull Map<String, ResourcePack> getPacks() {
Expand All @@ -52,18 +57,39 @@ public SessionLoadResourcePacksEventImpl(GeyserSession session, Map<String, Reso
return List.copyOf(packs.values());
}

@Override
public @NonNull List<ResourcePackCDNEntry> cdnEntries() {
return List.copyOf(cdnEntries.values());
}

@Override
public boolean register(@NonNull ResourcePack resourcePack) {
String packID = resourcePack.manifest().header().uuid().toString();
if (packs.containsValue(resourcePack) || packs.containsKey(packID)) {
if (packs.containsValue(resourcePack) || packs.containsKey(packID) || cdnEntries.containsKey(packID)) {
return false;
}
packs.put(resourcePack.manifest().header().uuid().toString(), resourcePack);
return true;
}

@Override
public boolean register(@NonNull ResourcePackCDNEntry entry) {
String packID = entry.uuid().toString();
if (packs.containsKey(packID) || cdnEntries.containsKey(packID) || cdnEntries.containsValue(entry)) {
return false;
}
cdnEntries.put(packID, entry);
return true;
}

@Override
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.containsKey(uuid.toString())) {
return cdnEntries.remove(uuid.toString()) != null;
} else {
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ public static boolean isPre1_20_10(GeyserSession session) {
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.
*
Expand Down