Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-19 22:40:18 +01:00
API event for skull blocks & let register via URL
Signed-off-by: Joshua Castle <26531652+Kas-tle@users.noreply.github.com>
Dieser Commit ist enthalten in:
Ursprung
1e75b88215
Commit
9007ee4630
@ -33,7 +33,7 @@ import org.geysermc.event.Event;
|
|||||||
/**
|
/**
|
||||||
* Called on Geyser's startup when looking for custom blocks. Custom blocks must be registered through this event.
|
* Called on Geyser's startup when looking for custom blocks. Custom blocks must be registered through this event.
|
||||||
*
|
*
|
||||||
* This event will not be called if the "add-custom-blocks" setting is disabled in the Geyser config.
|
* This event will not be called if the "add-non-bedrock-items" setting is disabled in the Geyser config.
|
||||||
*/
|
*/
|
||||||
public abstract class GeyserDefineCustomBlocksEvent implements Event {
|
public abstract class GeyserDefineCustomBlocksEvent implements Event {
|
||||||
|
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
package org.geysermc.geyser.api.event.lifecycle;
|
||||||
|
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.geysermc.event.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on Geyser's startup when looking for custom skulls. Custom skulls must be registered through this event.
|
||||||
|
*
|
||||||
|
* This event will not be called if the "add-non-bedrock-items" setting is disabled in the Geyser config.
|
||||||
|
*/
|
||||||
|
public abstract class GeyserDefineCustomSkullsEvent implements Event {
|
||||||
|
/**
|
||||||
|
* The type of texture provided
|
||||||
|
*/
|
||||||
|
public enum SkullTextureType {
|
||||||
|
USERNAME,
|
||||||
|
UUID,
|
||||||
|
PROFILE,
|
||||||
|
SKIN_URL
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the given username, UUID, or base64 encoded profile as a custom skull blocks
|
||||||
|
* @param texture the username, UUID, or base64 encoded profile
|
||||||
|
* @param type the type of texture provided
|
||||||
|
*/
|
||||||
|
public abstract void registerCustomSkull(@NonNull String texture, @NonNull SkullTextureType type);
|
||||||
|
}
|
@ -41,8 +41,11 @@ public class GeyserCustomSkullConfiguration {
|
|||||||
@JsonProperty("player-uuids")
|
@JsonProperty("player-uuids")
|
||||||
private List<String> playerUUIDs;
|
private List<String> playerUUIDs;
|
||||||
|
|
||||||
@JsonProperty("textures")
|
@JsonProperty("player-profiles")
|
||||||
private List<String> textures;
|
private List<String> playerProfiles;
|
||||||
|
|
||||||
|
@JsonProperty("skin-urls")
|
||||||
|
private List<String> skinUrls;
|
||||||
|
|
||||||
public List<String> getPlayerUsernames() {
|
public List<String> getPlayerUsernames() {
|
||||||
return Objects.requireNonNullElse(playerUsernames, Collections.emptyList());
|
return Objects.requireNonNullElse(playerUsernames, Collections.emptyList());
|
||||||
@ -52,7 +55,11 @@ public class GeyserCustomSkullConfiguration {
|
|||||||
return Objects.requireNonNullElse(playerUUIDs, Collections.emptyList());
|
return Objects.requireNonNullElse(playerUUIDs, Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<String> getTextures() {
|
public List<String> getPlayerProfiles() {
|
||||||
return Objects.requireNonNullElse(textures, Collections.emptyList());
|
return Objects.requireNonNullElse(playerProfiles, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getPlayerSkinUrls() {
|
||||||
|
return Objects.requireNonNullElse(skinUrls, Collections.emptyList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,10 @@ package org.geysermc.geyser.registry.populator;
|
|||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
|
import lombok.NonNull;
|
||||||
import org.geysermc.geyser.GeyserBootstrap;
|
import org.geysermc.geyser.GeyserBootstrap;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
|
import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCustomSkullsEvent;
|
||||||
import org.geysermc.geyser.configuration.GeyserCustomSkullConfiguration;
|
import org.geysermc.geyser.configuration.GeyserCustomSkullConfiguration;
|
||||||
import org.geysermc.geyser.pack.SkullResourcePackManager;
|
import org.geysermc.geyser.pack.SkullResourcePackManager;
|
||||||
import org.geysermc.geyser.registry.BlockRegistries;
|
import org.geysermc.geyser.registry.BlockRegistries;
|
||||||
@ -69,58 +71,114 @@ public class CustomSkullRegistryPopulator {
|
|||||||
|
|
||||||
BlockRegistries.CUSTOM_SKULLS.set(new Object2ObjectOpenHashMap<>());
|
BlockRegistries.CUSTOM_SKULLS.set(new Object2ObjectOpenHashMap<>());
|
||||||
|
|
||||||
List<String> textures = new ArrayList<>(skullConfig.getTextures());
|
List<String> profiles = new ArrayList<>(skullConfig.getPlayerProfiles());
|
||||||
// TODO see if this can be cleaned up any better
|
|
||||||
for (String username : skullConfig.getPlayerUsernames()) {
|
List<String> usernames = new ArrayList<>(skullConfig.getPlayerUsernames());
|
||||||
try {
|
|
||||||
String texture = SkinProvider.requestTexturesFromUsername(username).get();
|
List<String> uuids = new ArrayList<>(skullConfig.getPlayerUUIDs());
|
||||||
if (texture == null) {
|
|
||||||
GeyserImpl.getInstance().getLogger().error("Unable to request skull textures for " + username + " This skull will not be added as a custom block.");
|
List<String> skinUrls = new ArrayList<>(skullConfig.getPlayerSkinUrls());
|
||||||
continue;
|
|
||||||
}
|
GeyserImpl.getInstance().getEventBus().fire(new GeyserDefineCustomSkullsEvent() {
|
||||||
textures.add(texture);
|
@Override
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
public void registerCustomSkull(@NonNull String texture, @NonNull SkullTextureType type) {
|
||||||
GeyserImpl.getInstance().getLogger().error("Unable to request skull textures for " + username + " This skull will not be added as a custom block.", e);
|
switch (type) {
|
||||||
|
case USERNAME -> usernames.add(texture);
|
||||||
|
case UUID -> uuids.add(texture);
|
||||||
|
case PROFILE -> profiles.add(texture);
|
||||||
|
case SKIN_URL -> skinUrls.add(texture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (String uuid : skullConfig.getPlayerUUIDs()) {
|
});
|
||||||
try {
|
|
||||||
String uuidDigits = uuid.replace("-", "");
|
for (String username : usernames) {
|
||||||
if (uuidDigits.length() != 32) {
|
String profile = getProfileFromUsername(username);
|
||||||
GeyserImpl.getInstance().getLogger().error("Invalid skull uuid " + uuid + " This skull will not be added as a custom block.");
|
if (profile != null) {
|
||||||
continue;
|
String skinUrl = getSkinUrl(profile);
|
||||||
|
if (skinUrl != null) {
|
||||||
|
skinUrls.add(skinUrl);
|
||||||
}
|
}
|
||||||
String texture = SkinProvider.requestTexturesFromUUID(uuid).get();
|
|
||||||
if (texture == null) {
|
|
||||||
GeyserImpl.getInstance().getLogger().error("Unable to request skull textures for " + uuid + " This skull will not be added as a custom block.");
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
textures.add(texture);
|
}
|
||||||
} catch (InterruptedException | ExecutionException e) {
|
for (String uuid : uuids) {
|
||||||
GeyserImpl.getInstance().getLogger().error("Unable to request skull textures for " + uuid + " This skull will not be added as a custom block.", e);
|
String profile = getProfileFromUuid(uuid);
|
||||||
|
if (profile != null) {
|
||||||
|
String skinUrl = getSkinUrl(profile);
|
||||||
|
if (skinUrl != null) {
|
||||||
|
skinUrls.add(skinUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (String texture : textures) {
|
for (String profile : profiles) {
|
||||||
try {
|
String skinUrl = getSkinUrl(profile);
|
||||||
SkinManager.GameProfileData profileData = SkinManager.GameProfileData.loadFromJson(texture);
|
if (skinUrl != null) {
|
||||||
if (profileData == null) {
|
skinUrls.add(skinUrl);
|
||||||
GeyserImpl.getInstance().getLogger().warning("Skull texture " + texture + " contained no skins and will not be added as a custom block.");
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String skinUrl : skinUrls) {
|
||||||
try {
|
try {
|
||||||
String skinUrl = profileData.skinUrl();
|
|
||||||
String skinHash = skinUrl.substring(skinUrl.lastIndexOf("/") + 1);
|
String skinHash = skinUrl.substring(skinUrl.lastIndexOf("/") + 1);
|
||||||
SkullResourcePackManager.cacheSkullSkin(skinUrl, skinHash);
|
SkullResourcePackManager.cacheSkullSkin(skinUrl, skinHash);
|
||||||
BlockRegistries.CUSTOM_SKULLS.register(skinHash, new CustomSkull(skinHash));
|
BlockRegistries.CUSTOM_SKULLS.register(skinHash, new CustomSkull(skinHash));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
GeyserImpl.getInstance().getLogger().error("Failed to cache skin for skull texture " + texture + " This skull will not be added as a custom block.", e);
|
GeyserImpl.getInstance().getLogger().error("Failed to cache skin for skull texture " + skinUrl + " This skull will not be added as a custom block.", e);
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
GeyserImpl.getInstance().getLogger().error("Skull texture " + texture + " is invalid and will not be added as a custom block.", e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GeyserImpl.getInstance().getLogger().debug("Registered " + BlockRegistries.CUSTOM_SKULLS.get().size() + " custom skulls as custom blocks.");
|
GeyserImpl.getInstance().getLogger().info("Registered " + BlockRegistries.CUSTOM_SKULLS.get().size() + " custom skulls as custom blocks.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the skin URL from a base64 encoded profile
|
||||||
|
* @param profile the base64 encoded profile
|
||||||
|
* @return the skin URL or null if the profile is invalid
|
||||||
|
*/
|
||||||
|
private static String getSkinUrl(String profile) {
|
||||||
|
try {
|
||||||
|
SkinManager.GameProfileData profileData = SkinManager.GameProfileData.loadFromJson(profile);
|
||||||
|
if (profileData == null) {
|
||||||
|
GeyserImpl.getInstance().getLogger().warning("Skull texture " + profile + " contained no skins and will not be added as a custom block.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return profileData.skinUrl();
|
||||||
|
} catch (IOException e) {
|
||||||
|
GeyserImpl.getInstance().getLogger().error("Skull texture " + profile + " is invalid and will not be added as a custom block.", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the base64 encoded profile from a player's username
|
||||||
|
* @param username the player username
|
||||||
|
* @return the base64 encoded profile or null if the request failed
|
||||||
|
*/
|
||||||
|
private static String getProfileFromUsername(String username) {
|
||||||
|
try {
|
||||||
|
return SkinProvider.requestTexturesFromUsername(username).get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
GeyserImpl.getInstance().getLogger().error("Unable to request skull textures for " + username + " This skull will not be added as a custom block.", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the base64 encoded profile from a player's UUID
|
||||||
|
* @param uuid the player UUID
|
||||||
|
* @return the base64 encoded profile or null if the request failed
|
||||||
|
*/
|
||||||
|
private static String getProfileFromUuid(String uuid) {
|
||||||
|
try {
|
||||||
|
String uuidDigits = uuid.replace("-", "");
|
||||||
|
if (uuidDigits.length() != 32) {
|
||||||
|
GeyserImpl.getInstance().getLogger().error("Invalid skull uuid " + uuid + " This skull will not be added as a custom block.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return SkinProvider.requestTexturesFromUUID(uuid).get();
|
||||||
|
} catch (InterruptedException | ExecutionException e) {
|
||||||
|
GeyserImpl.getInstance().getLogger().error("Unable to request skull textures for " + uuid + " This skull will not be added as a custom block.", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,16 +165,6 @@ custom-skull-render-distance: 32
|
|||||||
# This option requires a restart of Geyser in order to change its setting.
|
# This option requires a restart of Geyser in order to change its setting.
|
||||||
add-non-bedrock-items: true
|
add-non-bedrock-items: true
|
||||||
|
|
||||||
# Whether to allow custom blocks to be added.
|
|
||||||
# This should only need to be disabled if using a proxy that does not use the "transfer packet" style of server switching.
|
|
||||||
add-custom-blocks: true
|
|
||||||
|
|
||||||
# Whether to allow some custom skulls to be translated as custom blocks and displayed in the inventory and on entities.
|
|
||||||
# This requires `add-custom-blocks` and `allow-custom-skulls` to be enabled.
|
|
||||||
# This will generate a resource pack for Bedrock players and enables `force-resource-packs`.
|
|
||||||
# Custom skulls can be added in `custom-skulls.yml`
|
|
||||||
add-custom-skull-blocks: false
|
|
||||||
|
|
||||||
# Bedrock prevents building and displaying blocks above Y127 in the Nether.
|
# Bedrock prevents building and displaying blocks above Y127 in the Nether.
|
||||||
# This config option works around that by changing the Nether dimension ID to the End ID.
|
# This config option works around that by changing the Nether dimension ID to the End ID.
|
||||||
# The main downside to this is that the entire Nether will have the same red fog rather than having different fog for each biome.
|
# The main downside to this is that the entire Nether will have the same red fog rather than having different fog for each biome.
|
||||||
|
@ -21,5 +21,9 @@ player-uuids:
|
|||||||
# - 8b8d8e8f-2759-47c6-acb5-5827de8a72b8
|
# - 8b8d8e8f-2759-47c6-acb5-5827de8a72b8
|
||||||
|
|
||||||
# The long string of characters found in the NBT of custom player heads
|
# The long string of characters found in the NBT of custom player heads
|
||||||
textures:
|
player-profiles:
|
||||||
# - ewogICJ0aW1lc3RhbXAiIDogMTY1NzMyMjIzOTgzMywKICAicHJvZmlsZUlkIiA6ICJjZGRiZTUyMGQwNDM0YThiYTFjYzlmYzkyZmRlMmJjZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJBbWJlcmljaHUiLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTkwNzkwYzU3ZTE4MWVkMTNhZGVkMTRjNDdlZTJmN2M4ZGUzNTMzZTAxN2JhOTU3YWY3YmRmOWRmMWJkZTk0ZiIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9
|
# - ewogICJ0aW1lc3RhbXAiIDogMTY1NzMyMjIzOTgzMywKICAicHJvZmlsZUlkIiA6ICJjZGRiZTUyMGQwNDM0YThiYTFjYzlmYzkyZmRlMmJjZiIsCiAgInByb2ZpbGVOYW1lIiA6ICJBbWJlcmljaHUiLAogICJ0ZXh0dXJlcyIgOiB7CiAgICAiU0tJTiIgOiB7CiAgICAgICJ1cmwiIDogImh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTkwNzkwYzU3ZTE4MWVkMTNhZGVkMTRjNDdlZTJmN2M4ZGUzNTMzZTAxN2JhOTU3YWY3YmRmOWRmMWJkZTk0ZiIsCiAgICAgICJtZXRhZGF0YSIgOiB7CiAgICAgICAgIm1vZGVsIiA6ICJzbGltIgogICAgICB9CiAgICB9CiAgfQp9
|
||||||
|
|
||||||
|
# The URL of the skin on Minecraft's skin server
|
||||||
|
skin-urls:
|
||||||
|
# - http://textures.minecraft.net/texture/a90790c57e181ed13aded14c47ee2f7c8de3533e017ba957af7bdf9df1bde94f
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren