Skip to content

Commit

Permalink
feat(Integration): Add Geyser Integration
Browse files Browse the repository at this point in the history
  • Loading branch information
mcchampions committed Oct 12, 2024
1 parent 5604717 commit 5ca9e92
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 1 deletion.
15 changes: 14 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@
<id>codemc-repo</id>
<url>https://repo.codemc.io/repository/maven-public/</url>
</repository>
<repository>
<!-- Geyser-->
<id>opencollab-snapshot</id>
<url>https://repo.opencollab.dev/main/</url>
</repository>
</repositories>

<build>
Expand Down Expand Up @@ -238,7 +243,7 @@
<dependency>
<groupId>com.github.mcchampions.dough</groupId>
<artifactId>dough-api</artifactId>
<version>0facd94827</version>
<version>7136585ffd</version>
</dependency>
<dependency>
<groupId>io.papermc</groupId>
Expand Down Expand Up @@ -414,5 +419,13 @@
<version>b7a2bd8</version>
<scope>compile</scope>
</dependency>

<!-- Geyser -->
<dependency>
<groupId>org.geysermc.geyser</groupId>
<artifactId>api</artifactId>
<version>2.4.2-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.logging.Level;

import lombok.Getter;
import me.qscbm.slimefun4.integrations.GeyserIntegration;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
Expand Down Expand Up @@ -138,6 +139,10 @@ private void onServerLoad() {
* This method is called when the {@link Server} has finished loading all its {@link Plugin Plugins}.
*/
private void onServerStart() {
// Geyser Integration (custom skulls)
load("Geyser-Spigot", integration -> {
new GeyserIntegration().register();
});
try {
// Load Protection plugin integrations
protectionManager = new ProtectionManager(plugin);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package me.qscbm.slimefun4.integrations;

import io.github.bakedlibs.dough.config.Config;
import io.github.thebusybiscuit.slimefun4.api.items.SlimefunItem;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import me.qscbm.slimefun4.utils.NBTUtils;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class GeyserIntegration {
public void register() {
Slimefun.logger().info("开始加载自定义粘液科技Geyser支持");

Config config = new Config(new File("plugins/Geyser-Spigot/custom-skulls.yml"));
List<String> l = config.getStringList("skin-hashes");
int successCount = 0;
int errorCount = 0;
for (SlimefunItem slimefunItem : Slimefun.getRegistry().getAllSlimefunItems()) {
ItemStack itemStack = slimefunItem.getItem();
if (itemStack.getType() != Material.PLAYER_HEAD) {
continue;
}
ItemMeta m = itemStack.getItemMeta();
if (!(m instanceof SkullMeta meta)) {
errorCount++;
continue;
}
String textureCode = NBTUtils.getTexture(meta);
if (textureCode == null) {
errorCount++;
continue;
}
String[] ts = textureCode.split("/");
String hash = ts[ts.length - 1];
if (!l.contains(hash)) {
l.add(hash);
}
successCount++;
}
String[] i = {"player-names", "player-uuids", "player-profiles"};
for (String t : i) {
if (config.getStringList(t).isEmpty()) {
config.setValue(t, new ArrayList<>());
}
}
config.setValue("skin-hashes", l);
config.save();
Slimefun.logger().info("成功加载" + successCount + "个自定义头颅");
Slimefun.logger().info("加载失败" + errorCount + "个自定义头颅");
Slimefun.logger().warning("完成加载自定义粘液科技Geyser支持,如果不生效请重启服务器");
}
}
105 changes: 105 additions & 0 deletions src/main/java/me/qscbm/slimefun4/utils/NBTUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package me.qscbm.slimefun4.utils;

import com.destroystokyo.paper.profile.ProfileProperty;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import io.github.bakedlibs.dough.reflection.ReflectionUtils;
import io.github.thebusybiscuit.slimefun4.implementation.Slimefun;
import org.bukkit.Bukkit;
import org.bukkit.inventory.meta.SkullMeta;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Base64;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class NBTUtils {
public static final String CRAFTBUKKIT_PACKAGE_NAME = Bukkit.getServer().getClass().getPackage().getName();

public static final String VERSION;

private static final Class<?> CRAFT_SKULL_META_CLAZZ;

private static final Field SKULL_PROFILE;

private static final Class<?> RESOLVABLE_PROFILE;

private static Method RESOLVABLE_PROFILE_GAME_PROFILE_GETTER = null;

private static final Method PROPERTY_NAME_GETTER;
private static final Method PROPERTY_VALUE_GETTER;

static {
String detectedVersion = CRAFTBUKKIT_PACKAGE_NAME.substring(CRAFTBUKKIT_PACKAGE_NAME.lastIndexOf('.') + 1);
if (!detectedVersion.startsWith("v")) {
// Paper or something...
detectedVersion = VersionUtils.getBukkitVersion();
}
VERSION = detectedVersion;
try {
CRAFT_SKULL_META_CLAZZ = Class.forName(CRAFTBUKKIT_PACKAGE_NAME + ".inventory." + "CraftMetaSkull");
SKULL_PROFILE = CRAFT_SKULL_META_CLAZZ.getDeclaredField("profile");
SKULL_PROFILE.setAccessible(true);
} catch (ClassNotFoundException | NoSuchFieldException e) {
throw new RuntimeException(e);
}
Class<?> resolvableProfile;
try {
resolvableProfile = Class.forName("net.minecraft.world.item.component.ResolvableProfile");
RESOLVABLE_PROFILE_GAME_PROFILE_GETTER = ReflectionUtils.getMethod(resolvableProfile, "f");
} catch (ClassNotFoundException e) {
resolvableProfile = null;
}
RESOLVABLE_PROFILE = resolvableProfile;
PROPERTY_NAME_GETTER = ReflectionUtils.getMethod(Property.class, "getName");
PROPERTY_VALUE_GETTER = ReflectionUtils.getMethod(Property.class, "getValue");
}

public static String getTexture(SkullMeta skullMeta) {
try {
Object pro = SKULL_PROFILE.get(skullMeta);
if (RESOLVABLE_PROFILE != null && RESOLVABLE_PROFILE.isInstance(pro)) {
if (RESOLVABLE_PROFILE_GAME_PROFILE_GETTER != null) {
pro = RESOLVABLE_PROFILE_GAME_PROFILE_GETTER.invoke(pro);
}
}

if (pro == null) {
return null;
}
GameProfile profile = (GameProfile) pro;
Collection<Property> properties = profile.getProperties().values();
for (Property prop : properties) {
String texture = null;
if (PROPERTY_NAME_GETTER != null) {
if ("textures".equals(PROPERTY_NAME_GETTER.invoke(prop))) {
texture = new String(Base64.getDecoder().decode((String) PROPERTY_VALUE_GETTER.invoke(prop)));
}
} else {
if ("textures".equals(prop.name())) {
texture = new String(Base64.getDecoder().decode(prop.value()));
}
}
return getMatch(texture, "\\{\"url\":\"(.*?)\"\\}");
}
return null;
} catch (IllegalAccessException | InvocationTargetException e) {
Slimefun.logger().warning(e.getMessage());
return null;
}
}

@SuppressWarnings("SameParameterValue")
private static String getMatch(String string, String regex) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(string);
if (matcher.find()) {
return matcher.group(1);
} else {
return null;
}
}
}
1 change: 1 addition & 0 deletions src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ softdepend:
- ItemsAdder
- Vault
- Orebfuscator
- Geyser-Spigot

# We hook into these plugins too, but they depend on Slimefun.
loadBefore:
Expand Down

0 comments on commit 5ca9e92

Please sign in to comment.