From 578c66e2fe6de9e83f9e9ad1b8508a1def97aae1 Mon Sep 17 00:00:00 2001 From: owlnull Date: Thu, 23 Apr 2020 06:39:54 +0500 Subject: [PATCH 1/4] Add skins support via SkinsRestorer plugin --- .../src/main/java/org/dynmap/DynmapCore.java | 6 +- .../src/main/java/org/dynmap/PlayerFaces.java | 32 ++++++---- .../main/java/org/dynmap/SkinUrlProvider.java | 7 +++ spigot/build.gradle | 4 ++ .../java/org/dynmap/bukkit/DynmapPlugin.java | 15 +++++ .../bukkit/SkinsRestorerSkinUrlProvider.java | 58 +++++++++++++++++++ spigot/src/main/resources/configuration.txt | 3 + spigot/src/main/resources/plugin.yml | 2 +- 8 files changed, 113 insertions(+), 14 deletions(-) create mode 100644 DynmapCore/src/main/java/org/dynmap/SkinUrlProvider.java create mode 100644 spigot/src/main/java/org/dynmap/bukkit/SkinsRestorerSkinUrlProvider.java diff --git a/DynmapCore/src/main/java/org/dynmap/DynmapCore.java b/DynmapCore/src/main/java/org/dynmap/DynmapCore.java index 1cd166a3..dd6fa9bb 100644 --- a/DynmapCore/src/main/java/org/dynmap/DynmapCore.java +++ b/DynmapCore/src/main/java/org/dynmap/DynmapCore.java @@ -30,7 +30,6 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -104,6 +103,7 @@ public class DynmapCore implements DynmapCommonAPI { public ComponentManager componentManager = new ComponentManager(); public DynmapListenerManager listenerManager = new DynmapListenerManager(this); public PlayerFaces playerfacemgr; + public SkinUrlProvider skinUrlProvider; public Events events = new Events(); public String deftemplatesuffix = ""; private DynmapMapCommands dmapcmds = new DynmapMapCommands(); @@ -155,6 +155,10 @@ public class DynmapCore implements DynmapCommonAPI { /* Constructor for core */ public DynmapCore() { } + + public void setSkinUrlProvider(SkinUrlProvider skinUrlProvider) { + this.skinUrlProvider = skinUrlProvider; + } /* Cleanup method */ public void cleanup() { diff --git a/DynmapCore/src/main/java/org/dynmap/PlayerFaces.java b/DynmapCore/src/main/java/org/dynmap/PlayerFaces.java index de0f591c..83da181a 100644 --- a/DynmapCore/src/main/java/org/dynmap/PlayerFaces.java +++ b/DynmapCore/src/main/java/org/dynmap/PlayerFaces.java @@ -106,12 +106,16 @@ public class PlayerFaces { } private class LoadPlayerImages implements Runnable { + private SkinUrlProvider mSkinUrlProvider; public final String playername; public final String playerskinurl; - public LoadPlayerImages(String playername, String playerskinurl, UUID playeruuid) { + + public LoadPlayerImages(String playername, String playerskinurl, UUID playeruuid, SkinUrlProvider skinUrlProvider) { this.playername = playername; this.playerskinurl = playerskinurl; + mSkinUrlProvider = skinUrlProvider; } + public void run() { boolean has_8x8 = storage.hasPlayerFaceImage(playername, FaceType.FACE_8X8); boolean has_16x16 = storage.hasPlayerFaceImage(playername, FaceType.FACE_16X16); @@ -123,16 +127,20 @@ public class PlayerFaces { BufferedImage img = null; try { if(fetchskins && (refreshskins || missing_any)) { - URL url = null; - if (skinurl.equals("") == false) { - url = new URL(skinurl.replace("%player%", URLEncoder.encode(playername, "UTF-8"))); - } - else if (playerskinurl != null) { - url = new URL(playerskinurl); - } - if (url != null) { - img = ImageIO.read(url); /* Load skin for player */ - } + URL url = null; + + if (mSkinUrlProvider == null) { + if (!skinurl.equals("")) { + url = new URL(skinurl.replace("%player%", URLEncoder.encode(playername, "UTF-8"))); + } else if (playerskinurl != null) { + url = new URL(playerskinurl); + } + } else { + url = mSkinUrlProvider.getSkinUrl(playername); + } + + if (url != null) + img = ImageIO.read(url); /* Load skin for player */ } } catch (IOException iox) { Debug.debug("Error loading skin for '" + playername + "' - " + iox); @@ -292,7 +300,7 @@ public class PlayerFaces { core.listenerManager.addListener(EventType.PLAYER_JOIN, new PlayerEventListener() { @Override public void playerEvent(DynmapPlayer p) { - Runnable job = new LoadPlayerImages(p.getName(), p.getSkinURL(), p.getUUID()); + Runnable job = new LoadPlayerImages(p.getName(), p.getSkinURL(), p.getUUID(), core.skinUrlProvider); if(fetchskins) MapManager.scheduleDelayedJob(job, 0); else diff --git a/DynmapCore/src/main/java/org/dynmap/SkinUrlProvider.java b/DynmapCore/src/main/java/org/dynmap/SkinUrlProvider.java new file mode 100644 index 00000000..bdb4e53d --- /dev/null +++ b/DynmapCore/src/main/java/org/dynmap/SkinUrlProvider.java @@ -0,0 +1,7 @@ +package org.dynmap; + +import java.net.URL; + +public interface SkinUrlProvider { + URL getSkinUrl(String playerName); +} \ No newline at end of file diff --git a/spigot/build.gradle b/spigot/build.gradle index 33c63e82..532c389b 100644 --- a/spigot/build.gradle +++ b/spigot/build.gradle @@ -5,6 +5,9 @@ repositories { maven { url 'https://jitpack.io' } + maven { + url 'https://repo.codemc.org/repository/maven-snapshots' + } } dependencies { @@ -41,6 +44,7 @@ dependencies { implementation(project(':bukkit-helper-115')) { transitive = false } + implementation 'com:skinsrestorer:13.7.5-20191221.213031-7@jar' } processResources { diff --git a/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java b/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java index 03e652c4..579fc4f1 100644 --- a/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java +++ b/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java @@ -105,6 +105,7 @@ import org.dynmap.renderer.DynmapBlockState; import org.dynmap.utils.MapChunkCache; import org.dynmap.utils.Polygon; import org.dynmap.utils.VisibilityLimit; +import skinsrestorer.bukkit.SkinsRestorer; public class DynmapPlugin extends JavaPlugin implements DynmapAPI { private DynmapCore core; @@ -896,6 +897,20 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { this.setEnabled(false); return; } + + /* Skins support via SkinsRestorer */ + SkinsRestorer skinsRestorer = null; + + if (core.configuration.getBoolean("skinsrestorer-integration", false)) + skinsRestorer = JavaPlugin.getPlugin(SkinsRestorer.class); + + SkinsRestorerSkinUrlProvider skinUrlProvider = null; + + if (skinsRestorer != null) + skinUrlProvider = new SkinsRestorerSkinUrlProvider(skinsRestorer); + + core.setSkinUrlProvider(skinUrlProvider); + /* See if we need to wait before enabling core */ if(!readyToEnable()) { Listener pl = new Listener() { diff --git a/spigot/src/main/java/org/dynmap/bukkit/SkinsRestorerSkinUrlProvider.java b/spigot/src/main/java/org/dynmap/bukkit/SkinsRestorerSkinUrlProvider.java new file mode 100644 index 00000000..54fa98dc --- /dev/null +++ b/spigot/src/main/java/org/dynmap/bukkit/SkinsRestorerSkinUrlProvider.java @@ -0,0 +1,58 @@ +package org.dynmap.bukkit; + +import org.dynmap.SkinUrlProvider; +import org.json.simple.parser.JSONParser; +import org.json.simple.parser.ParseException; +import org.json.simple.JSONObject; +import skinsrestorer.bukkit.SkinsRestorer; +import skinsrestorer.bukkit.SkinsRestorerBukkitAPI; +import skinsrestorer.shared.utils.ReflectionUtil; + +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public class SkinsRestorerSkinUrlProvider implements SkinUrlProvider { + private JSONParser mJsonParser; + private SkinsRestorerBukkitAPI mSkinsRestorerApi; + + SkinsRestorerSkinUrlProvider(SkinsRestorer skinsRestorer) { + mJsonParser = new JSONParser(); + mSkinsRestorerApi = skinsRestorer.getSkinsRestorerBukkitAPI(); + } + + @Override + public URL getSkinUrl(String playerName) { + String skinName = mSkinsRestorerApi.getSkinName(playerName); + + Object skinDataProperty = mSkinsRestorerApi.getSkinData(skinName == null ? playerName : skinName); + String skinDataPropertyValue; + + try { + skinDataPropertyValue = (String) ReflectionUtil.invokeMethod(skinDataProperty, "getValue"); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + + byte[] skinDataBytes = Base64.getDecoder().decode(skinDataPropertyValue); + + JSONObject skinData; + + try { + skinData = (JSONObject) mJsonParser.parse(new String(skinDataBytes, StandardCharsets.UTF_8)); + } catch (ParseException ex) { + ex.printStackTrace(); + return null; + } + + try { + return new URL((String) ((JSONObject) ((JSONObject) skinData.get("textures")).get("SKIN")).get("url")); + } catch (MalformedURLException ex) { + ex.printStackTrace(); + } + + return null; + } +} \ No newline at end of file diff --git a/spigot/src/main/resources/configuration.txt b/spigot/src/main/resources/configuration.txt index 9de84ea6..68b42d43 100644 --- a/spigot/src/main/resources/configuration.txt +++ b/spigot/src/main/resources/configuration.txt @@ -280,6 +280,9 @@ custom-colors-support: true # Customize URL used for fetching player skins (%player% is macro for name) skin-url: "http://skins.minecraft.net/MinecraftSkins/%player%.png" +# Enable skins via SkinsRestorer plugin instead of internal legacy implementation (disabled by default) +#skinsrestorer-integration: true + render-triggers: #- playermove #- playerjoin diff --git a/spigot/src/main/resources/plugin.yml b/spigot/src/main/resources/plugin.yml index a1e91eff..26d415fb 100644 --- a/spigot/src/main/resources/plugin.yml +++ b/spigot/src/main/resources/plugin.yml @@ -3,7 +3,7 @@ main: org.dynmap.bukkit.DynmapPlugin version: "${version}-${buildnumber}" authors: [mikeprimm] website: "https://www.reddit.com/r/Dynmap/" -softdepend: [ Permissions, PermissionEx, bPermissions, PermissionsBukkit, GroupManager, LuckPerms, Vault ] +softdepend: [ Permissions, PermissionEx, bPermissions, PermissionsBukkit, GroupManager, LuckPerms, Vault, SkinsRestorer ] commands: dynmap: description: Controls Dynmap. From 1ffa0e24ff08db9ddd80259ff63bbf7c8ff0362b Mon Sep 17 00:00:00 2001 From: owlnull Date: Thu, 23 Apr 2020 07:23:12 +0500 Subject: [PATCH 2/4] Fix NullPointerException in SkinsRestorerSkinUrlProvider.getSkinUrl during joins player without skin --- .../java/org/dynmap/bukkit/SkinsRestorerSkinUrlProvider.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spigot/src/main/java/org/dynmap/bukkit/SkinsRestorerSkinUrlProvider.java b/spigot/src/main/java/org/dynmap/bukkit/SkinsRestorerSkinUrlProvider.java index 54fa98dc..a1336fc1 100644 --- a/spigot/src/main/java/org/dynmap/bukkit/SkinsRestorerSkinUrlProvider.java +++ b/spigot/src/main/java/org/dynmap/bukkit/SkinsRestorerSkinUrlProvider.java @@ -27,6 +27,10 @@ public class SkinsRestorerSkinUrlProvider implements SkinUrlProvider { String skinName = mSkinsRestorerApi.getSkinName(playerName); Object skinDataProperty = mSkinsRestorerApi.getSkinData(skinName == null ? playerName : skinName); + + if (skinDataProperty == null) + return null; + String skinDataPropertyValue; try { From ef2a45ab2aef7db1115c2f0ac6d7c91f5811e7b8 Mon Sep 17 00:00:00 2001 From: owlnull Date: Sun, 26 Apr 2020 13:09:12 +0500 Subject: [PATCH 3/4] Made dependency SkinsRestorer compileOnly --- spigot/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spigot/build.gradle b/spigot/build.gradle index 532c389b..92f42254 100644 --- a/spigot/build.gradle +++ b/spigot/build.gradle @@ -11,11 +11,12 @@ repositories { } dependencies { - compile group: 'org.bukkit', name: 'bukkit', version:'1.7.10-R0.1-SNAPSHOT' + compile group: 'org.bukkit', name: 'bukkit', version:'1.7.10-R0.1-SNAPSHOT' compile 'com.nijikokun.bukkit:Permissions:3.1.6' compile 'me.lucko.luckperms:luckperms-api:4.3' compile 'net.luckperms:api:5.0' compile('com.github.MilkBowl:VaultAPI:1.7') { transitive = false } + compileOnly 'com:skinsrestorer:13.7.5-20191221.213031-7@jar' compile project(":dynmap-api") compile project(path: ":DynmapCore", configuration: "shadow") compile group: 'ru.tehkode', name: 'PermissionsEx', version:'1.19.1' @@ -44,7 +45,6 @@ dependencies { implementation(project(':bukkit-helper-115')) { transitive = false } - implementation 'com:skinsrestorer:13.7.5-20191221.213031-7@jar' } processResources { From c7cb56bc1de9bba295ddfcd668f877026aa4bf3d Mon Sep 17 00:00:00 2001 From: owlnull Date: Tue, 28 Apr 2020 15:10:25 +0500 Subject: [PATCH 4/4] Fix plugin crash caused by SkinsRestorer integration SkinsRestorer integration now just shows warning instead of plugin crash when SkinsRestorer not installed and integration enabled --- .../java/org/dynmap/bukkit/DynmapPlugin.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java b/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java index 579fc4f1..4307f67a 100644 --- a/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java +++ b/spigot/src/main/java/org/dynmap/bukkit/DynmapPlugin.java @@ -899,15 +899,18 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI { } /* Skins support via SkinsRestorer */ - SkinsRestorer skinsRestorer = null; - - if (core.configuration.getBoolean("skinsrestorer-integration", false)) - skinsRestorer = JavaPlugin.getPlugin(SkinsRestorer.class); - SkinsRestorerSkinUrlProvider skinUrlProvider = null; - if (skinsRestorer != null) - skinUrlProvider = new SkinsRestorerSkinUrlProvider(skinsRestorer); + if (core.configuration.getBoolean("skinsrestorer-integration", false)) { + SkinsRestorer skinsRestorer = (SkinsRestorer) getServer().getPluginManager().getPlugin("SkinsRestorer"); + + if (skinsRestorer == null) { + Log.warning("SkinsRestorer integration can't be enabled because SkinsRestorer not installed"); + } else { + skinUrlProvider = new SkinsRestorerSkinUrlProvider(skinsRestorer); + Log.info("SkinsRestorer integration enabled"); + } + } core.setSkinUrlProvider(skinUrlProvider);