Sıfırdan Minigames Kodlama #2 (Faydalı API'ler)

Ne düşünüyorsun? (Birden çok şık işaretlenebilir)


  • Kullanılan toplam oy
    8

java10

kız çava bana kahve yap
Mesajlar
513
En iyi cevaplar
0
Beğeniler
586
Puanları
1,090
Ruh hali
önceki dersimde on enable ve on disable a kadar geldik ve .jar ımızı oluşturmuştuk :) şimdi bir kaç api yazıcaz bunlar minigames yazarken çok işimize yarıycak apiler olacak,

öncelikle haritaları ve oyuncu bilgilerini kaydetmemiz(save/load) için oos ois ten yararlanacağız kullanımı basittir,

Kod:
public static <T> void save(T obj, String path) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path));
        oos.writeObject(obj);
        oos.flush();
        oos.close();
    }
    public static <T> T load(String path)throws Exception {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
        T result = (T) ois.readObject();
        ois.close();
        return result;
    }
bu kodu isterseniz açacağınız api package ine koyabilirsiniz ya da düz çalışmak istiyorsanız her şeyi tek class ta yapabilirsiniz(önerilmez)

başka ufak bir api;

Kod:
public static String chatcolor(String s){
        return ChatColor.translateAlternateColorCodes('&', s);
    }
bu p.sendMessage(ChatColor.Green + "selam" + ChatColor.GOLD + " nasılsın?"); gibi uzun yazılardan kurtarım buna dönüştürücek: p.sendMessage(API.chatcolor("&aSelam nasılsın?")); & bunu oyunda kullandığımız gibi kullanabilicez uzun ve fazla renkli cümlelerde işimize yarıycaktır bu koduda api class ınıza atabilirsiniz

Kod:
public static void dinleyicilerikaydet(Plugin p, Listener... listeners){
        Arrays.stream(listeners).forEach(listener -> Bukkit.getPluginManager().registerEvents(listener,p));
    }
belki başınıza gelmiştir diye bunu veriyorum bu kolayca listenerları kaydetmenize yarıycak peki bu olmadan nasıl yapıyorduk;
getServer().getPluginManager().registerEvents(this, new ListenerNeyseArtık());
ee bu kodu kullanırsak nasıl yazıcaz;
dinleyicilerikaydet(this, new ListenerNeyse(), new DiğerBirListener(), new Baska(), new BLaba(), new BaşkalarıdaVar());
gibi işimizi kolaylaştırıcaktır ilk this yazmamın sebebi methodu incelerseniz ilk değerin Pluginin yani main class ın yerini belirtmenizi istiyor ilk dersimizde söylediğim extends JavaPlugin yaptığımız class ımızı yazıyoruz, bu kodu main class a da koyabilirsiniz isteyen istediği yere koyar eee peki api classına koyarsam nasıl "this" yazıcam onun içinse şöyle bir kod vereyim,
Kod:
public static AnaClassİsmi getPlugin(){
        return (AnaClassİsmi)Bukkit.getPluginManager().getPlugin("Plugininizinİsmi");
    }
bu kod ana classınızı getPlugin() yaparak içindeki public verilerine rahatça erişmenizi sağlar instance denen lanet şey ile uğraşmak zorunda kalmazsınız peki dinleyicileri nasıl yazıcam buna,
Kod:
dinleyicilerikaydet(AnaClass.getPlugin(), new Test1(), new Test12(), new Test13());
şeklinde, AnaClass.getPlugin() bunun anlamı main class ta "this" in anlamı ile aynıdır class ı seçer

gelelim configapi mize bunu ben çok kullanıyorum sizede tavsiye ederim,
Kod:
public class ConfigAPI {

    private File file = null;
    private FileConfiguration fileConfiguration = null;

    public ConfigAPI(String s, Plugin p){
        file = new File(p.getDataFolder(), s + ".yml");
        fileConfiguration = YamlConfiguration.loadConfiguration(file);
        saveFile();
    }

    public Object get(String path){
        return getConfig().get(path);
    }

    public void set(String path, Object o){
        getConfig().set(path,o);
        saveFile();
    }

    public FileConfiguration getConfig(){
        if (fileConfiguration == null){
            loadFile();
        }
        return fileConfiguration;
    }

    public void saveFile(){
        try {
            getConfig().save(file);
        }catch (IOException e){}
    }

    public void loadFile(){
        if (file.exists()){
            try {
                getConfig().load(file);
            }catch (IOException | InvalidConfigurationException e){}
        }else{
            saveFile();
        }
    }

    public void createSection(String s) {
        fileConfiguration.createSection(s);
        saveFile();
    }

    public ConfigurationSection getConfigurationSection(String path){
        return getConfig().getConfigurationSection(path);
    }
}
bu apiyi nasıl kullanabilirim;
öncelikle main classınıza oluşturacağınız özel config i belirtmemiz gerekiyor,
Kod:
public ConfigAPI configismimiz;
bu kodu main classın üst taraflarına doğru atalım ve on enable a yazmamız gereken şeyleri yazalım;
Kod:
configismimiz= new ConfigAPI("dosyamızınismi", this);
"this" yazmamın sebebi kodun main class ta olması ama siz anaclass.getPlugin() de yapabilirisiniz(başka bir class ta tutuyorsanız config listesini)

minigameslerde en önemli şeylerden biri görsellik bunun içinse güzel apilerimiz var :)
scoreboardapi:
Kod:
public class ScoreBoardAPI {

    private Scoreboard scoreboard;

    private String title;
    private Map<String, Integer> scores;
    private List<Team> teams;

    public ScoreBoardAPI(String title) {
        this.scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
        this.title = title;
        this.scores = Maps.newLinkedHashMap();
        this.teams = Lists.newArrayList();
    }

    public void blankLine() {
        add(" ");
    }

    public void add(String text) {
        add(text, null);
    }

    public void add(String text, Integer score) {
        Preconditions.checkArgument(text.length() < 48, "text cannot be over 48 characters in length");
        text = fixDuplicates(text);
        scores.put(text, score);
    }

    private String fixDuplicates(String text) {
        while (scores.containsKey(text))
            text += "§r";
        if (text.length() > 48)
            text = text.substring(0, 47);
        return text;
    }

    private Map.Entry<Team, String> createTeam(String text) {
        String result = "";
        if (text.length() <= 16)
            return new AbstractMap.SimpleEntry<>(null, text);
        Team team = scoreboard.registerNewTeam("text-" + scoreboard.getTeams().size());
        Iterator<String> iterator = Splitter.fixedLength(16).split(text).iterator();
        team.setPrefix(iterator.next());
        result = iterator.next();
        if (text.length() > 32)
            team.setSuffix(iterator.next());
        teams.add(team);
        return new AbstractMap.SimpleEntry<>(team, result);
    }

    public void build() {
        Objective obj = scoreboard.registerNewObjective((title.length() > 16 ? title.substring(0, 15) : title), "dummy");
        obj.setDisplayName(title);
        obj.setDisplaySlot(DisplaySlot.SIDEBAR);

        int index = scores.size();

        for (Map.Entry<String, Integer> text : scores.entrySet()) {
            Map.Entry<Team, String> team = createTeam(text.getKey());
            Integer score = text.getValue() != null ? text.getValue() : index;
            OfflinePlayer player = Bukkit.getOfflinePlayer(team.getValue());
            if (team.getKey() != null)
                team.getKey().addPlayer(player);
            obj.getScore(player).setScore(score);
            index -= 1;
        }
    }

    public void reset() {
        title = null;
        scores.clear();
        for (Team t : teams)
            t.unregister();
        teams.clear();
    }

    public Scoreboard getScoreboard() {
        return scoreboard;
    }

    public void send(Player... players) {
        for (Player p : players)
            p.setScoreboard(scoreboard);
    }

}
scoreboard apimiz bu şekilde nasıl kullanılır;
Kod:
ScoreboardsAPI score = new ScoreboardsAPI(chatcolor("&aTest Title"));
score.add(chatcolor("&eTest Scoreboard 1. Satır"));
score.add(chatcolor("&eTest Scoreboard 2. Satır"));
score.build();
score.send(player, başkaoyuncu, diğeroyuncular, başkaoyuncuvarsa, otherplayer);
bunu timer a koyarsanız sürekli featherboard gibi güncellenecektir "flash" sorunu yoktur, peki ben bu sınırsız kalıyor ise nasıl silicem;
Kod:
score.reset();
bu kod ile scoreboard u silebilirsiniz.
bu şekilde kullanılıyor peki görüntüsü nasıl;
titleapi;
Kod:
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;

import java.lang.reflect.Constructor;

public class TitleAPI {

    public static void sendPacket(Player player, Object packet) {
        try {
            Object handle = player.getClass().getMethod("getHandle").invoke(player);
            Object playerConnection = handle.getClass().getField("playerConnection").get(handle);
            playerConnection.getClass().getMethod("sendPacket", getNMSClass("Packet")).invoke(playerConnection, packet);
        } catch (Exception var4) {
            var4.printStackTrace();
        }

    }

    public static Class<?> getNMSClass(String name) {
        String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];

        try {
            return Class.forName("net.minecraft.server." + version + "." + name);
        } catch (ClassNotFoundException var3) {
            var3.printStackTrace();
            return null;
        }
    }

    public static void sendTitle(Player player, Integer fadeIn, Integer stay, Integer fadeOut, String title, String subtitle) {
            try {
                Object e;
                Constructor subtitleConstructor;
                if (title != null) {
                    title = ChatColor.translateAlternateColorCodes('&', title);
                    title = title.replaceAll("%player%", player.getDisplayName());
                    e = getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0].getField("TIMES").get((Object)null);
                    Object chatTitle = getNMSClass("IChatBaseComponent").getDeclaredClasses()[0].getMethod("a", String.class).invoke((Object)null, "{\"text\":\"" + title + "\"}");
                    subtitleConstructor = getNMSClass("PacketPlayOutTitle").getConstructor(getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0], getNMSClass("IChatBaseComponent"), Integer.TYPE, Integer.TYPE, Integer.TYPE);
                    Object titlePacket = subtitleConstructor.newInstance(e, chatTitle, fadeIn, stay, fadeOut);
                    sendPacket(player, titlePacket);
                    e = getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0].getField("TITLE").get((Object)null);
                    chatTitle = getNMSClass("IChatBaseComponent").getDeclaredClasses()[0].getMethod("a", String.class).invoke((Object)null, "{\"text\":\"" + title + "\"}");
                    subtitleConstructor = getNMSClass("PacketPlayOutTitle").getConstructor(getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0], getNMSClass("IChatBaseComponent"));
                    titlePacket = subtitleConstructor.newInstance(e, chatTitle);
                    sendPacket(player, titlePacket);
                }

                if (subtitle != null) {
                    subtitle = ChatColor.translateAlternateColorCodes('&', subtitle);
                    subtitle = subtitle.replaceAll("%player%", player.getDisplayName());
                    e = getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0].getField("TIMES").get((Object)null);
                    Object chatSubtitle = getNMSClass("IChatBaseComponent").getDeclaredClasses()[0].getMethod("a", String.class).invoke((Object)null, "{\"text\":\"" + title + "\"}");
                    subtitleConstructor = getNMSClass("PacketPlayOutTitle").getConstructor(getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0], getNMSClass("IChatBaseComponent"), Integer.TYPE, Integer.TYPE, Integer.TYPE);
                    Object subtitlePacket = subtitleConstructor.newInstance(e, chatSubtitle, fadeIn, stay, fadeOut);
                    sendPacket(player, subtitlePacket);
                    e = getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0].getField("SUBTITLE").get((Object)null);
                    chatSubtitle = getNMSClass("IChatBaseComponent").getDeclaredClasses()[0].getMethod("a", String.class).invoke((Object)null, "{\"text\":\"" + subtitle + "\"}");
                    subtitleConstructor = getNMSClass("PacketPlayOutTitle").getConstructor(getNMSClass("PacketPlayOutTitle").getDeclaredClasses()[0], getNMSClass("IChatBaseComponent"), Integer.TYPE, Integer.TYPE, Integer.TYPE);
                    subtitlePacket = subtitleConstructor.newInstance(e, chatSubtitle, fadeIn, stay, fadeOut);
                    sendPacket(player, subtitlePacket);
                }
            } catch (Exception var13) {
                var13.printStackTrace();
            }
    }

    public static void clearTitle(Player player) {
        sendTitle(player, 0, 0, 0, "", "");
    }
}
kod bu şekilde apimiz nasıl kullanılır;
Kod:
TitleAPI.sendTitle(oyuncu, 30, 600, 30,"ANA BAŞLIK" ,"alt yazı" );
bu şekilde kullanılıyor anlamını yazıyım;
ilk 30: title ın ekrana giriş zamanı
600: title ın ekranda durma süresi
ikinci 30: title ın ekrandan koybolma zamanı
peki ekranda olan title ı nasıl silebilirim;
Kod:
TitleAPI.clearTitle(oyuncu);
bu şekildede ekranda olan title siliniyor.
actionbarapi;
actionbar ı api yi kurmadan önce on enable a eklememiz gereken bazı şeyler var;
bu on enable a değil üstüne eklenmesi gerekiyor;
Kod:
public static String nmsver;
private static boolean useOldMethods = false;
public static boolean works = true;
bunu ekledikten sonra actionbar ımızı belirtelim;
Kod:
nmsver = Bukkit.getServer().getClass().getPackage().getName();
nmsver = nmsver.substring(nmsver.lastIndexOf(".") + 1);
if (nmsver.equalsIgnoreCase("v1_8_R1") || nmsver.startsWith("v1_7_")) {
    useOldMethods = true;
}
new ActionBarAPI(nmsver, useOldMethods, works);
bu kod on enable a ekiyoruz ve ekledikten sonra api mize geçelim;
Kod:
public class ActionBarAPI {

    static String nmsver;
    static boolean useOldMethods;
    static boolean works;

    public ActionBarAPI(String a, boolean b, boolean c){
        nmsver = a;
        useOldMethods = b;
        works = c;
    }

    public static void sendActionBar(Player player, String message) {
        if (!player.isOnline()) {
            return; // Player may have logged out
        }
        if (nmsver.startsWith("v1_12_")) {
            sendActionBarPost112(player, message);
        } else {
            sendActionBarPre112(player, message);
        }
    }

    private static void sendActionBarPost112(Player player, String message) {
        if (!player.isOnline()) {
            return; // Player may have logged out
        }

        try {
            Class<?> craftPlayerClass = Class.forName("org.bukkit.craftbukkit." + nmsver + ".entity.CraftPlayer");
            Object craftPlayer = craftPlayerClass.cast(player);
            Object ppoc;
            Class<?> c4 = Class.forName("net.minecraft.server." + nmsver + ".PacketPlayOutChat");
            Class<?> c5 = Class.forName("net.minecraft.server." + nmsver + ".Packet");
            Class<?> c2 = Class.forName("net.minecraft.server." + nmsver + ".ChatComponentText");
            Class<?> c3 = Class.forName("net.minecraft.server." + nmsver + ".IChatBaseComponent");
            Class<?> chatMessageTypeClass = Class.forName("net.minecraft.server." + nmsver + ".ChatMessageType");
            Object[] chatMessageTypes = chatMessageTypeClass.getEnumConstants();
            Object chatMessageType = null;
            for (Object obj : chatMessageTypes) {
                if (obj.toString().equals("GAME_INFO")) {
                    chatMessageType = obj;
                }
            }
            Object o = c2.getConstructor(new Class<?>[]{String.class}).newInstance(message);
            ppoc = c4.getConstructor(new Class<?>[]{c3, chatMessageTypeClass}).newInstance(o, chatMessageType);
            Method m1 = craftPlayerClass.getDeclaredMethod("getHandle");
            Object h = m1.invoke(craftPlayer);
            Field f1 = h.getClass().getDeclaredField("playerConnection");
            Object pc = f1.get(h);
            Method m5 = pc.getClass().getDeclaredMethod("sendPacket", c5);
            m5.invoke(pc, ppoc);
        } catch (Exception ex) {
            ex.printStackTrace();
            works = false;
        }
    }

    private static void sendActionBarPre112(Player player, String message) {
        if (!player.isOnline()) {
            return; // Player may have logged out
        }

        try {
            Class<?> craftPlayerClass = Class.forName("org.bukkit.craftbukkit." + nmsver + ".entity.CraftPlayer");
            Object craftPlayer = craftPlayerClass.cast(player);
            Object ppoc;
            Class<?> c4 = Class.forName("net.minecraft.server." + nmsver + ".PacketPlayOutChat");
            Class<?> c5 = Class.forName("net.minecraft.server." + nmsver + ".Packet");
            if (useOldMethods) {
                Class<?> c2 = Class.forName("net.minecraft.server." + nmsver + ".ChatSerializer");
                Class<?> c3 = Class.forName("net.minecraft.server." + nmsver + ".IChatBaseComponent");
                Method m3 = c2.getDeclaredMethod("a", String.class);
                Object cbc = c3.cast(m3.invoke(c2, "{\"text\": \"" + message + "\"}"));
                ppoc = c4.getConstructor(new Class<?>[]{c3, byte.class}).newInstance(cbc, (byte) 2);
            } else {
                Class<?> c2 = Class.forName("net.minecraft.server." + nmsver + ".ChatComponentText");
                Class<?> c3 = Class.forName("net.minecraft.server." + nmsver + ".IChatBaseComponent");
                Object o = c2.getConstructor(new Class<?>[]{String.class}).newInstance(message);
                ppoc = c4.getConstructor(new Class<?>[]{c3, byte.class}).newInstance(o, (byte) 2);
            }
            Method m1 = craftPlayerClass.getDeclaredMethod("getHandle");
            Object h = m1.invoke(craftPlayer);
            Field f1 = h.getClass().getDeclaredField("playerConnection");
            Object pc = f1.get(h);
            Method m5 = pc.getClass().getDeclaredMethod("sendPacket", c5);
            m5.invoke(pc, ppoc);
        } catch (Exception ex) {
            ex.printStackTrace();
            works = false;
        }
    }

    public static void sendActionBar(final Player player, final String message, int duration) {
        sendActionBar(player, message);

        if (duration >= 0) {
            // Sends empty message at the end of the duration. Allows messages shorter than 3 seconds, ensures precision.
            new BukkitRunnable() {
                @Override
                public void run() {
                    sendActionBar(player, "");
                }
            }.runTaskLater(ANACLASS.getPlugin(), duration + 1);
        }

        // Re-sends the messages every 3 seconds so it doesn't go away from the player's screen.
        while (duration > 40) {
            duration -= 40;
            new BukkitRunnable() {
                @Override
                public void run() {
                    sendActionBar(player, message);
                }
            }.runTaskLater(ANACLASS.getPlugin(), (long) duration);
        }
    }

    public static void sendActionBarToAllPlayers(String message) {
        sendActionBarToAllPlayers(message, -1);
    }

    public static void sendActionBarToAllPlayers(String message, int duration) {
        for (Player p : Bukkit.getOnlinePlayers()) {
            sendActionBar(p, message, duration);
        }
    }
}
peki nasıl kullanıcaz;
sendActionBar(oyuncu, "actionbar mesajımız");
peki zamanlı yapmak istersem;
sendActionBar(oyuncu, "actionbar mesajımız", 10*20);
*20 yapmamın sebebi ise int in aslında long olması yani eğer 100 saniye yapacaksanız 100*20 yazmanız gererekiyor.
yine önemli bir api olan envanter i string e string i envantere çeviren apimiz bunu oyuncuların bilgilerini kaydetmede işimize yarıycak bildiğiniz gibi bir minigames odasına girerken oyuncunun envanterini kaydederiz ve oyun bitince geri veririz işte bu apide bunu sağlıyor;
Kod:
public class Base64CoderAPI {

    @NotNull
    public static String toBase64(Inventory inventory) {
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            BukkitObjectOutputStream dataOutput = new BukkitObjectOutputStream(outputStream);
            dataOutput.writeInt(inventory.getSize());
            dataOutput.writeUTF(inventory.getTitle());
            for (int i = 0; i < inventory.getSize(); i++) {
                dataOutput.writeObject(inventory.getItem(i));
            }
            dataOutput.close();
            return Base64Coder.encodeLines(outputStream.toByteArray());
        } catch (Exception e) {
            throw new IllegalStateException("Unable to save item stacks.", e);
        }
    }

    public static Inventory fromBase64(String data) throws IOException {
        try {
            ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(data));
            BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream);
            Inventory inventory = Bukkit.getServer().createInventory(null, dataInput.readInt(), dataInput.readUTF());
            for (int i = 0; i < inventory.getSize(); i++) {
                inventory.setItem(i, (ItemStack) dataInput.readObject());
            }
            dataInput.close();
            return inventory;
        } catch (ClassNotFoundException e) {
            throw new IOException("Unable to decode class type.", e);
        }
    }
peki nasıl kullanıcaz;
Kod:
String envanterstring = Base64CoderAPI.toBase64(oyuncu.getInventory());
Inventory envaterinkendi = Base64CoderAPI.fromBase64(string);
bu şekilde kullanılıyor, ayrıca,
Kod:
Inventory inv = null;
        try {
            inv = Base64CoderAPI.fromBase64(envanterstringiozel);
        } catch (IOException e) {
            e.printStackTrace();
        }

        p.getInventory().setContents(inv.getContents());
bu şekildede oyuncunun envanterini set yapmış olursunuz

Benden bu kadar diğer konumda görüşmek dileğiyle :dost:

(resimler, yazılar ve kodlar bana aittir alıntı yapabilirsiniz)
(konu biraz uzun ama okuyunca düşünsene sende minigames yazabiliceksin)


Etiketler: @KilllerDragons , @S4RP , @Za_ion101 , @Elfen , @Atomy , @Onurbey034 , @Spygrand , @ByAehn , @GodofMilker , @Frodox , @ShortPallMall , @MCTDark
 


Son düzenleme:

KilllerDragons

Kızıltaş Madencisi
Mesajlar
569
En iyi cevaplar
0
Beğeniler
143
Puanları
560
Ruh hali
Merak Ettiğim Bişi Var Bazı Minigameler Olur Sürüme Göre Title Kullanıyolar Mesela Onu Nasıl Yapıyorlar ?
 

java10

kız çava bana kahve yap
Mesajlar
513
En iyi cevaplar
0
Beğeniler
586
Puanları
1,090
Ruh hali
Merak Ettiğim Bişi Var Bazı Minigameler Olur Sürüme Göre Title Kullanıyolar Mesela Onu Nasıl Yapıyorlar ?
o iş nms ile yapılıyor ve benim yaptığım ise reflec hemen avataj ve dezavantajlarından bahsediyim;

nms:
çok fazla class oluşturman gerekiyor yani diyelimki 6 tane sürüm için 1.11.2 1.11.1 1.11 1.12 ibi bir sürü sürüm için yapmak istersen kaç sürüm yapıcaksan o kadar class oluşturman gerekiyor reflect e göre daha hızlı, nms tek bir sürüm için yapılacaksa mutlaka nms kullanılmalı reflecte göre classların satır sayısı çok fazla düşük

reflect:
tüm sürümer(actionbar ise actionbar ne zaman çıktıysa) için sadece tek classta her şeyi halledebiliyorsun ama hızı yavaş

hız konusuda gözle görülür mü bilmem ama bukkit forumunda reflectin yavaş nms nin hızlı olduğu söyleniyor bi bakıma doğru nms de benim yazdığım apinin %10 kadar bi satır sürüyor, satır sayıları çok yüksek ama çok fazla sürüm için yapılacaksa kesinlikle reflect tercih edilmeli,

peki ben bunu nasıl kullanıcam, öncelikle reflecti zaten yazdım konuda var nms yi anlatıyım;

öncelikle özel bir interface classı oluşturmalısın nedeni ise implements edeceğiz tüm actionbar classlarında önr. veriyim buna implements Listener listener classı interface tir yani i implements Listener yaptığın class aslında bir dinleyici class olduğunu söylersin class ın ırkı gibi mesela implements CommandExecutor da aynı şeydir o classın ırkı komut classıdır bizimde kendimize özel yazacağımız bi ırk olmalı oda actionbar dır biz buna sadece sendActionBar(); methodunu ekliycez ve biz onu kullanıcaz mantığını açıklamak gerekirse Actionbarları açtığımız class ların hepsini özel actionbar interface sini implements edicez diyelimki;
public interface ActionBar{bla bla bla}
böyle bir ırk classımız var ve biz bunu diğer nms lerde (actionbar classlarında) kullanıcaz normal listener ve commandexecutor gibi impl. edicez

public class ActionBar1_11_2 implements ActionBar{
bu şekilde yapıcaz ve içini impl. ettiğimiz classın içindeki methodu doldurucaz
}

hemen örn. kodlarla sana yardımcı olıyım;

özel ırk class ımız:
Kod:
package me.benim.interfacem.burada;

import org.bukkit.entity.Player;

public interface Actionbar {
    public void sendActionbar(Player p, String message);
}
bu şekilde bir ırk classı açalım ardından nms classlarımızı açalım istediğin sürüm olur(actionbarın misal olarak ne zaman çıktıysa o sürümün üstü olmalı altında zaten actionbar olmaz)
Kod:
package me.benim.interfacem.burada;

import net.minecraft.server.v1_8_R1.ChatSerializer;
import net.minecraft.server.v1_8_R1.IChatBaseComponent;
import net.minecraft.server.v1_8_R1.PacketPlayOutChat;
import org.bukkit.craftbukkit.v1_8_R1.entity.CraftPlayer;

import org.bukkit.entity.Player;

public class Actionbar_1_8_R1 implements Actionbar {

    @Override
    public void sendActionbar(Player p, String message) {
 
        IChatBaseComponent icbc = ChatSerializer.a("{\"text\": \"" + message + "\"}");
        PacketPlayOutChat bar = new PacketPlayOutChat(icbc, (byte) 2);
        ((CraftPlayer) p).getHandle().playerConnection.sendPacket(bar);
    }
}

bu şekilde nms classımız olur reflect class a göre ne kadar kısa dimi :)
ayrıca bunun gibi bir sürü class açabilirsin yalnız nms ler bazen değişiklik gösterebiliyor kodları mesela 1.11 de bu:
Kod:
IChatBaseComponent icbc = ChatSerializer.a("{\"text\": \"" + message + "\"}");
        PacketPlayOutChat bar = new PacketPlayOutChat(icbc, (byte) 2);
        ((CraftPlayer) p).getHandle().playerConnection.sendPacket(bar);
kodlar aynı olmaya bilir hepsini internetten bakman gerekiyor
şimdi main class ımıza dönelim ve on enable ın üstüne içine değil üstüne şunu yazalım
Kod:
private Actionbar actionbar;
ve yeni bi method açalım main classa:
Kod:
public Actionbar getActionbar() {
    return actionbar;
}
bu method ilede actionbarı kullanıcaz;
getActionbar().sendPlayer(...);
bunu yazdıktan sonra sürümümüzü belirticez yani bizim hangi sürüm olduğumuzu belirtip onu nms ile birleştiricez:
bi method açalım düzenli olması açısından main classa;
Kod:
private boolean setupActionbar() {
        String version;
        try {
            version = Bukkit.getServer().getClass().getPackage().getName().replace(".",  ",").split(",")[3];
        } catch (ArrayIndexOutOfBoundsException whatVersionAreYouUsingException) {
            return false;
        }
        getLogger().info("Your server is running version " + version);
        if (version.equals("v1_8_R1")) {
            actionbar = new Actionbar_1_8_R1();
        } else if (version.equals("v1_8_R2")) {
            actionbar = new Actionbar_1_8_R2();
        } else if (version.equals("v1_11_2 tam sürüm ismini bilmiyorum onun için "version" u bi console a yazdır on enableda sonra versionları if lere koy")){
            actionbar = new Actionbar_1_11_2_R1 vs vs tam bilmiyorum console a version u yazdır hangi sürümsen
        }
        return actionbar != null; // burdada eğer null ilse boolean ı false döndürücek
    }
bu kod bizim sürümümüzü doğrulıycak ve actionbar nms lerinden hangisini kullanıcaksan onu belirticek ama öncelikle hangi sürümler koyduğumuzu ve bizim hangi sürüm olduğumuz bilmemiz gerekiyor, işlemimiz tamamsa on enanble a dönelim ve;
Kod:
if (setupActionbar()) {
    Bukkit.getPluginManager().registerEvents(this, this);
    getLogger().info("Actionbar setup was successful!");
    getLogger().info("The plugin setup process is complete!");
} else {
    getLogger().severe("Failed to setup Actionbar!");
    getLogger().severe("Your server version is not compatible with this plugin!");
     Bukkit.getPluginManager().disablePlugin(this);
}
bu kodu on enable a ekledikten sonra işimiz tamamdır ee peki ben bunu nasıl kullanıcam;
bi örn. verelim;
Kod:
@EventHandler
    public void onJoin(PlayerJoinEvent event) {
        actionbar.sendActionbar(event.getPlayer(), "Sunucuya hoş geldin!");
    }
peki görüntüsü;

bu şekildede bir çıkışı var resim bana ait değildir kaynak kodları ve ingilizce anlatımı için:
https://www.spigotmc.org/wiki/nms-on-different-versions-without-reflection/
spigotun bu sitesinden yararlanabilirsin,

iyi günler.

Merak Ettiğim Bişi Var Bazı Minigameler Olur Sürüme Göre Title Kullanıyolar Mesela Onu Nasıl Yapıyorlar ?
bunu title'a da uyarlıyabilirsin aynı yöntem ile

hatalarım olduğunu düşünenler pm ya da yorum atarak nerede olduğunu belirtirse sevinirim.
 

Üst