[Util] Skull-Items mit eigenen Skins

Hier könnt ihr anderen Leuten helfen, indem ihr Anleitungen oder praktische Codesegmente zur Verfügung stellt.

[Util] Skull-Items mit eigenen Skins

Beitragvon Sep2703 » Di 14. Apr 2015, 19:14

Hey,

ich möchte die Util-Bibliothek heute noch um eine Klasse erweitern.
Hiermit möchte ich euch eine Klasse zur Verfügung stellen, die es möglich macht, eigene Skin-Köpfe in auf ItemStacks zu legen.
Diese können auch als TileEntities in der Welt platziert werden und behalten die eigene Textur.

Code
Code: Alles auswählen
  1. package test;
  2. import java.lang.reflect.Constructor;
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.Method;
  5. import java.util.Base64;
  6. import java.util.UUID;
  7. import org.bukkit.Bukkit;
  8. import org.bukkit.Location;
  9. import org.bukkit.Material;
  10. import org.bukkit.block.Block;
  11. import org.bukkit.inventory.ItemStack;
  12. import org.bukkit.inventory.meta.SkullMeta;
  13. import com.mojang.authlib.GameProfile;
  14. import com.mojang.authlib.properties.Property;
  15. public class ItemSkulls {
  16.    
  17.    private static Class<?> skullMetaClass, tileEntityClass, blockPositionClass;
  18.    private static int mcVersion;
  19.    
  20.    static {
  21.       String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
  22.       mcVersion = Integer.parseInt(version.replaceAll("[^0-9]", ""));
  23.       try {
  24.          skullMetaClass = Class.forName("org.bukkit.craftbukkit." + version + ".inventory.CraftMetaSkull");
  25.          tileEntityClass = Class.forName("net.minecraft.server." + version + ".TileEntitySkull");
  26.          if (mcVersion > 174) {
  27.             blockPositionClass = Class.forName("net.minecraft.server." + version + ".BlockPosition");
  28.          } else {
  29.             blockPositionClass = null;
  30.          }
  31.       } catch (ClassNotFoundException e) {
  32.          e.printStackTrace();
  33.       }
  34.    }
  35.    
  36.    /**
  37.     *
  38.     * @param skinURL The URL to the skin-image (full skin)
  39.     * @return The itemstack (SKULL_ITEM) with the given look (skin-image)
  40.     */
  41.    public static ItemStack getSkull(String skinURL) {
  42.       return getSkull(skinURL, 1);
  43.    }
  44.    
  45.    /**
  46.     *
  47.     * @param skinURL The URL to the skin-image (full skin)
  48.     * @param amount The amount of skulls (for ItemStack)
  49.     * @return The itemstack (SKULL_ITEM) with the given look (skin-image)
  50.     */
  51.    public static ItemStack getSkull(String skinURL, int amount) {
  52.       ItemStack skull = new ItemStack(Material.SKULL_ITEM, amount, (short) 3);
  53.       SkullMeta meta = (SkullMeta) skull.getItemMeta();
  54.       try {
  55.          Field profileField = skullMetaClass.getDeclaredField("profile");
  56.          profileField.setAccessible(true);
  57.          profileField.set(meta, getProfile(skinURL));
  58.       } catch (Exception ex) {
  59.          ex.printStackTrace();
  60.       }
  61.       skull.setItemMeta(meta);
  62.       return skull;
  63.    }
  64.    
  65.    /**
  66.     *
  67.     * @param loc The location to place the skull
  68.     * @param skinURL The url to the skin-image
  69.     * @return If the block at the given location was replaced with a skull
  70.     */
  71.    public static boolean setBlock(Location loc, String skinURL) {
  72.       return setBlock(loc.getBlock(), skinURL);
  73.    }
  74.    
  75.    /**
  76.     *
  77.     * @param block The block to set skull
  78.     * @param skinURL The url to the skin-image
  79.     * @return If the block at the given location was replaced with a skull
  80.     */
  81.    public static boolean setBlock(Block block, String skinURL) {
  82.       boolean flag = block.getType() == Material.SKULL;
  83.       if (!flag) {
  84.          block.setType(Material.SKULL);
  85.       }
  86.       try {
  87.          Object nmsWorld = block.getWorld().getClass().getMethod("getHandle").invoke(block.getWorld());
  88.          Object tileEntity = null;
  89.          
  90.          if (mcVersion <= 174) {
  91.             Method getTileEntity = nmsWorld.getClass().getMethod("getTileEntity", int.class, int.class, int.class);
  92.             tileEntity = tileEntityClass.cast(getTileEntity.invoke(nmsWorld, block.getX(), block.getY(), block.getZ()));
  93.          } else {
  94.             Method getTileEntity = nmsWorld.getClass().getMethod("getTileEntity", blockPositionClass);
  95.             tileEntity = tileEntityClass.cast(getTileEntity.invoke(nmsWorld, getBlockPositionFor(block.getX(), block.getY(), block.getZ())));
  96.          }
  97.          
  98.          tileEntityClass.getMethod("setGameProfile", GameProfile.class).invoke(tileEntity, getProfile(skinURL));
  99.       } catch (Exception ex) {
  100.          ex.printStackTrace();
  101.       }
  102.       return !flag;
  103.    }
  104.    
  105.    private static GameProfile getProfile(String skinURL) {
  106.       GameProfile profile = new GameProfile(UUID.randomUUID(), null);
  107.       String base64encoded = Base64.getEncoder().encodeToString(new String("{textures:{SKIN:{url:\"" + skinURL + "\"}}}").getBytes());
  108.       Property property = new Property("textures", base64encoded);
  109.       profile.getProperties().put("textures", property);
  110.       return profile;
  111.    }
  112.    
  113.    private static Object getBlockPositionFor(int x, int y, int z) {
  114.       Object blockPosition = null;
  115.       try {
  116.          Constructor<?> cons = blockPositionClass.getConstructor(int.class, int.class, int.class);
  117.          blockPosition = cons.newInstance(x, y, z);
  118.       } catch (Exception ex) {
  119.          ex.printStackTrace();
  120.       }
  121.       return blockPosition;
  122.    }
  123. }



Verwendung
Diese Klasse besitzt zwei wichtige (statische) Methoden: getSkull(String) bzw. getSkull(String, int) und setBlock(Location, String) bzw. setBlock(Block, String).
Ich werde hier einfach mal ein Verwendungsbeispiel schreiben:
Code: Alles auswählen
  1.          ItemStack skull = ItemSkulls.getSkull("http://textures.minecraft.net/texture/a116e69a845e227f7ca1fdde8c357c8c821ebd4ba619382ea4a1f87d4ae94");
  2.          p.getInventory().addItem(skull);

Effekt: Der Spieler bekommt einen Kopf mit der Textur von Notch ins Inventar gelegt. Statt der URL zum Skin von Notch lassen sich hier beliebige URLs angeben.
Der getSkull()-Methode kann auch noch ein Integer für die Anzahl der Items im ItemStack übergeben werden.

In einem Update wurde außerdem die setBlock-Methode neu implementiert. Sie ermöglicht es nun, Skulls in der Welt zu platzieren und diese zu verändern (auch hier sind eigene Texturen möglich).
Ein Methodenaufruf dazu könnte wie folgt aussehen:
Code: Alles auswählen
  1.          String skinURL = "http://textures.minecraft.net/texture/a116e69a845e227f7ca1f";
  2.          ItemSkulls.setBlock(meineLocation, skinURL);

(Die URL zum Skin von Notch habe ich aus Übersichtsgründen stark gekürzt)
Effekt: An der gegebenen Location wird ein Skull mit der Textur von Notch platziert.
Die setBlock-Methode gibt außerdem noch einen boolean zurück. Dieser steht auf true, wenn ein anderer Block für den Skull ersetzt werden musste. Falls an der Location bereits ein Skull war, liefert die Methode false.


Die Klasse ist versionsunabhängig (getestet mit Spigot 1.8.3 und 1.8), sollte jedoch sowohl in älteren Versionen, als auch später in neueren Versionen problemlos funktionieren. Falls Probleme auftreten, freue ich mich über eine Info, sodass ich mich darum kümmern kann.

Das war's auch schon - viel Spaß damit!
Zuletzt geändert von Sep2703 am Mi 15. Apr 2015, 09:44, insgesamt 2-mal geändert.
Du möchtest programmieren lernen oder dein Bukkit-/Spigot-Wissen erweitern?
Hier habe ich für dich kostenlose Tutorials: https://youtube.com/janhektor
Benutzeravatar
Sep2703
 
Beiträge: 677
Registriert: Mi 8. Jan 2014, 15:13
Wohnort: 127.0.0.1

Re: [Util] Skull-Items mit eigenen Skins

Beitragvon ZockTV » Di 14. Apr 2015, 19:56

Hey,
vielen Dank, dass du dir die Zeit/Mühe genommen/gemacht hast, diese für mich höchstwahrscheinlich in Zukunft noch SEHR wichtige Klasse zu schreiben. :mrgreen:

Ich denke, viele andere Leute können das auch gebrauchen, da es ziemlich nervig ist, wenn man sich für jeden Kopf einen eigenen Account kaufen zu müssen...

LG ZockTV
ZockTV
 

Re: [Util] Skull-Items mit eigenen Skins

Beitragvon Jofkos » Di 14. Apr 2015, 20:12

Wenn du schon so eine Util-Klasse schreibst, dann füg doch auch noch eine Methode um den Skin eines Kopfes als Block zu verändern ein. (z.B. so).
Zudem kannst du die "MCVersion" Methode auch in einer Zeile schreiben:
Code: Alles auswählen
  1. String NMSVersion = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
Jofkos

...........

..Bild
Benutzeravatar
Jofkos
 
Beiträge: 1537
Registriert: So 16. Jun 2013, 22:45

Re: [Util] Skull-Items mit eigenen Skins

Beitragvon crysis992 » Mi 15. Apr 2015, 08:40

Wie immer, super Arbeit :)
Benutzeravatar
crysis992
 
Beiträge: 148
Registriert: So 16. Jun 2013, 11:48

Re: [Util] Skull-Items mit eigenen Skins

Beitragvon Sep2703 » Mi 15. Apr 2015, 09:48

Vielen Dank für euer Feedback!

UPDATE
Ich habe die Klasse um eine weitere Funktion erweitert und ein paar Kleinigkeiten optimiert.
An dieser Stelle sei noch ein Dank an @Jofkos für die Idee mit den Skull-Blöcken und der kürzeren NMS-Version ausgerichtet.
Dieses Update bringt folgende Features:
  • Skulls in der Welt setzen (mit gegebener Location)
  • Skulls in der Welt setzen (mit gegebenen Block)
  • Abwärtskompatibilität bis hin zur 1.7* (1.6 vermutlich auch; ungetestet)
* Die Klasse ermittelt die verwendete Bukkit/Spigot-Version automatisch und ruft Methoden mit entsprechender Parametrisierung auf

Die Anleitung im Startpost wurde um ein weiteres Code-Beispiel ergänzt; dort steht ab sofort auch der neue Code zur Verfügung.

Viel Spaß damit ;)
Du möchtest programmieren lernen oder dein Bukkit-/Spigot-Wissen erweitern?
Hier habe ich für dich kostenlose Tutorials: https://youtube.com/janhektor
Benutzeravatar
Sep2703
 
Beiträge: 677
Registriert: Mi 8. Jan 2014, 15:13
Wohnort: 127.0.0.1

Re: [Util] Skull-Items mit eigenen Skins

Beitragvon zwoerni » Do 23. Apr 2015, 08:12

Erstmal coole Klasse. Das Problem, welches ich jetzt habe: Ich habe einen Skin von einer URL angegeben, sagen wir mal x.de/skin.png nun habe ich den Skin geändert - Skin hat sich nach mehreren Tagen warten nicht verändert. Dann habe ich den Pfad geändert x.de/skin/skin.png - ebenfalls ein paar Tage gewartet, jedoch ohne Erfolg. Kann es sein, dass der Skin in irgendeiner Weise von Mojang gecached wird?
Benutzeravatar
zwoerni
 
Beiträge: 25
Registriert: Mo 15. Sep 2014, 15:20
Wohnort: Halle (Saale) - Sachsen Anhalt

Re: [Util] Skull-Items mit eigenen Skins

Beitragvon _PowerFox_ » Do 7. Mai 2015, 21:17

Hi.

Ich benutze Spigot 1.8.3 und besitze Java 8 doch irgendwie kennt eclipse den Base64 import nicht?

mfg
Benutzeravatar
_PowerFox_
 
Beiträge: 127
Registriert: Fr 9. Mai 2014, 20:13

Re: [Util] Skull-Items mit eigenen Skins

Beitragvon zwoerni » Sa 9. Mai 2015, 11:07

@_PowerFox_, du kannst den Base64Encoder von apache nehmen:

Code: Alles auswählen
  1. import org.apache.commons.codec.binary.Base64;


@Sep2703, die Klasse wird in der 1.8.4 nicht mehr funktionieren, da die Sicherheitslücke dort gefixt wurde.
Benutzeravatar
zwoerni
 
Beiträge: 25
Registriert: Mo 15. Sep 2014, 15:20
Wohnort: Halle (Saale) - Sachsen Anhalt

Re: [Util] Skull-Items mit eigenen Skins

Beitragvon ilouHD » Sa 9. Mai 2015, 11:09

zwoerni hat geschrieben:@_PowerFox_, du kannst den Base64Encoder von apache nehmen:

Code: Alles auswählen
  1. import org.apache.commons.codec.binary.Base64;


@Sep2703, die Klasse wird in der 1.8.4 nicht mehr funktionieren, da die Sicherheitslücke dort gefixt wurde.

Was ist das für ne Sicherheitslücke?
Die Sicherheitslücke war doch die eine da, wo Server gecrasht sind, weil zu viele NBT-Daten versendet wurden, oder nicht?
Bild
Benutzeravatar
ilouHD
 
Beiträge: 1733
Registriert: Do 9. Jan 2014, 14:49

Re: [Util] Skull-Items mit eigenen Skins

Beitragvon Sep2703 » Sa 9. Mai 2015, 11:53

ilouHD hat geschrieben:Was ist das für ne Sicherheitslücke?
Die Sicherheitslücke war doch die eine da, wo Server gecrasht sind, weil zu viele NBT-Daten versendet wurden, oder nicht?

Du sprichst von einer Sicherheitslücke, die vor kurzem gefixed wurde. Wer sagt, dass es nicht noch weitere Sicherheitslücken gibt?
In diesem Fall ist die Sicherheit unter Umständen aus folgendem Grund bedroht:
Der Client lädt die Bild-Datei automatisch herunter. Wenn du dort ein 5 GB Bild hinterlegst, wird das vermutlich stark auf die Internetleitung des Spielers gehen. Eventuell ist es sogar möglich, dort eine komplett andere Datei zu hinterlegen. Dann könnte es vielleicht auch mal gefährlich werden...
Du möchtest programmieren lernen oder dein Bukkit-/Spigot-Wissen erweitern?
Hier habe ich für dich kostenlose Tutorials: https://youtube.com/janhektor
Benutzeravatar
Sep2703
 
Beiträge: 677
Registriert: Mi 8. Jan 2014, 15:13
Wohnort: 127.0.0.1

Nächste

Zurück zu Anleitungen

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste