Mob Spawner'dan Item Çıkartma

utsukushihito

Marangoz
Mesajlar
50
En iyi cevaplar
0
Beğeniler
15
Puanları
40
Selam gençler, mob spawner'ı nasıl nbt değişikliği yaparak içinden item çıkartmayı göstereceğim.

Öncelikle bize lazım olan Util'imiz:
Java:
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

public class NMSUtils {

    public static String getVersion() {
        String name = Bukkit.getServer().getClass().getPackage().getName();
        String version = name.substring(name.lastIndexOf('.') + 1) + ".";
        return version;
    }

    public static Class<?> getNMSClass(String className) {
        String fullName = "net.minecraft.server." + getVersion() + className;
        Class<?> clazz = null;
        try {
            clazz = Class.forName(fullName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return clazz;
    }

    public static boolean NMSClassExists(String className) {
        String fullName = "net.minecraft.server." + getVersion() + className;
        try {
            Class.forName(fullName);
            return true;
        } catch (Exception e) {

        }
        return false;
    }

    public static Class<?> getOBCClass(String className) {
        String fullName = "org.bukkit.craftbukkit." + getVersion() + className;
        Class<?> clazz = null;
        try {
            clazz = Class.forName(fullName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return clazz;
    }

    public static Class<?> getClassFromPath(String path) {
        Class<?> clazz = null;
        try {
            clazz = Class.forName(path);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return clazz;
    }

    public static Object getHandle(Object obj) {
        try {
            return getMethod(obj.getClass(), "getHandle").invoke(obj);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Field getField(Class<?> clazz, String name) {
        try {
            Field field = clazz.getDeclaredField(name);
            field.setAccessible(true);
            return field;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Method getMethod(Class<?> clazz, String name, Class<?>... args) {
        for (Method m : clazz.getMethods())
            if (m.getName().equals(name)
                    && (args.length == 0 || ClassListEqual(args,
                    m.getParameterTypes()))) {
                m.setAccessible(true);
                return m;
            }
        return null;
    }

    public static Class<?> getInnerClass(Class<?> c, String className){
        Class<?> clazz = null;
        try {
            for(Class<?> cl : c.getDeclaredClasses()){
                if(cl.getSimpleName().equals(className)){
                    clazz = cl;
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return clazz;
    }

    public static boolean ClassListEqual(Class<?>[] l1, Class<?>[] l2) {
        boolean equal = true;
        if (l1.length != l2.length)
            return false;
        for (int i = 0; i < l1.length; i++)
            if (l1 != l2) {
                equal = false;
                break;
            }
        return equal;
    }

    public static void sendPacket(Player p, Object packet) {
        try {
            Method getHandle = NMSUtils.getMethod(p.getClass(),"getHandle");
            Object entityPlayer = getHandle.invoke(p);
            Object pConnection = NMSUtils.getField(entityPlayer.getClass(),"playerConnection").get(entityPlayer);
            Method sendMethod = NMSUtils.getMethod(pConnection.getClass(),"sendPacket", getNMSClass("Packet"));
            sendMethod.invoke(pConnection, packet);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}


NMSUtils.class'ımız bu şekilde.

Java:
private static void setItemSpawner19R1(Player player, Location location) {
        try {

            // player'ın elinde ki itemstack i kaydet.
           // elindeki itemi setItemInMainHand methodu ile istediğiniz itemi belirleyin belki arguman olarak onu koyabilirsin method içine de yazabilirsiniz
          // elindeki itemi değiştirdikten sonra ItemStack itemStack = p.getInventory().getItemInMainHand(); bu veriyi işletiyoruz.

            Class<?> blockPosition = NMSUtils.getNMSClass("BlockPosition");

            Object craftWorld = NMSUtils.getOBCClass("CraftWorld").cast(location.getWorld());

            Object worldServer = NMSUtils.getHandle(craftWorld);

            Object blockPositionCons = blockPosition.
                    getConstructor(int.class, int.class, int.class).
                    newInstance(location.getBlockX(), location.getBlockY(), location.getBlockZ());

            Object tileEntityMobSpawner = NMSUtils.getMethod(worldServer.getClass(),"getTileEntity",blockPosition).invoke(worldServer,blockPositionCons);

            Class<?> nbtTagCompound = NMSUtils.getNMSClass("NBTTagCompound");
            Class<?> nbtBase = NMSUtils.getNMSClass("NBTBase");

            Object nbtTileEntity = nbtTagCompound.
                    getConstructor().
                    newInstance();

            NMSUtils.getMethod(tileEntityMobSpawner.getClass(),"save",nbtTagCompound).
                    invoke(tileEntityMobSpawner,nbtTileEntity);

            Object nbtItemStack = nbtTagCompound.
                    getConstructor().
                    newInstance();

            Object nbtItemStackTag = nbtTagCompound.
                    getConstructor().
                    newInstance();

            Class<?> craftItemStack = NMSUtils.getClassFromPath("org.bukkit.craftbukkit." + NMSUtils.getVersion() + "inventory.CraftItemStack");

            Object nmsItemStack = craftItemStack.getMethod("asNMSCopy",ItemStack.class).invoke(null,itemStack);

            NMSUtils.getMethod(nmsItemStack.getClass(),"save",nbtItemStackTag.getClass()).
                    invoke(nmsItemStack,nbtItemStackTag);

            NMSUtils.getMethod(nbtItemStack.getClass(), "setString",String.class,String.class).
                    invoke(nbtItemStack,"id","Item");

            NMSUtils.getMethod(nbtTagCompound,"set",String.class,nbtBase).
                    invoke(nbtItemStack,"Item",nbtBase.cast(nbtItemStackTag));

            NMSUtils.getMethod(nbtTagCompound, "set",String.class,nbtBase).
                    invoke(nbtTileEntity,"SpawnData",nbtBase.cast(nbtItemStack));

            NMSUtils.getMethod(nbtTagCompound, "remove",String.class).
                    invoke(nbtTileEntity,"SpawnPotentials");

            NMSUtils.getMethod(nbtTagCompound, "setShort",String.class,short.class).
                    invoke(nbtTileEntity,"SpawnCount",(short)2);

            NMSUtils.getMethod(nbtTagCompound, "setInt",String.class,int.class).
                    invoke(nbtTileEntity,"MinSpawnDelay",20);

            NMSUtils.getMethod(nbtTagCompound,"setInt",String.class,int.class).
                    invoke(nbtTileEntity,"MaxSpawnDelay",20);

            NMSUtils.getMethod(nbtTagCompound,"setShort",String.class,short.class).
                    invoke(nbtTileEntity,"SpawnRange",(short)2);

            NMSUtils.getMethod(nbtTagCompound,"setShort",String.class,short.class).
                    invoke(nbtTileEntity,"RequiredPlayerRange",(short)10);

            NMSUtils.getMethod(tileEntityMobSpawner.getClass(),"a",nbtTagCompound).
                    invoke(tileEntityMobSpawner,nbtTagCompound.cast(nbtTileEntity));

           // en son kısıma da en yukarıda oyuncunun elinde ki eski itemi burada geri yüklememiz gerekiyor
          // p.getInventory().setItemInMainHand(eskiItemStack); ile bunu methodu uyguluyoruz sonrasında
          //  p.updateInventory(); methodu ile envanterini yeniliyoruz playerın, methodumuz tamamdır.
       
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Buda mob spawner'ın nbt değişikliği yaparak item çıkartmasını sağlıyor.

Methodu anlatmak gerekirse;

method 2 adet argümanla çalışıyor gördüğünüz gibi, player'ı almamda ki amaç elinde ki itemi çekmektir direkt olarak ItemStack olarak yaparsanız çalışmıyor, öncelikle player'ın elinde ki itemi değiştirip sonra o itemi ItemStack olarak çektikten ve veriyi kenara bir yere koyduktan sonra oyuncunun elinde ki itemi yeniden eski haline çeviriyoruz. Sonrası ise mâlum location'dan mob spawner'ın olacağı belirliyoruz ancak şöyle bir olay var, mob spawner'ı eline verirken mob spawner'ın nbt'sini değiştirseniz bile, mob spawner'ı yere koyduğu an default spawner(pig spawner)'a dönüşücektir, buda demek oluyor ki yere koyduktan sonra nbt'sini değiştirmeliyiz, event'imiz tabii ki BlockPlaceEvent olacaktır, block koyulduktan sonra setItemSpawner(player, event.getBlock().getLocation()); olarak yapmanızdır.

ek: method yalnızca 1.9 da çalışıyor, elimde 1.13 e kadar olan methodlar var ve çoğunda farklılık söz konusu hepsini yazmak istemedim, minecraft'ın wikipedi'sinden nbt değişiklerine bakarak 1.13 e kadar NMSUtils.... kısımlarındaki "" (tırnak) içinde ki yazıları değiştirip sürüme uygun yapabilirsiniz.
 



Üst