- Katılım
- 3 Haziran 2019
- Mesajlar
- 235
- Elmaslar
- 252
- Puanlar
- 7.295
- Yaş
- 22
- Yer
- Türkiye
- Discord İzni
- Minecraft
- GrimOK
- whyshiro_
Bu makale ilk bölümün devamı niteliğindedir. Eğer ilk bölümde yapmış olduğumuz "ProtocolManager", "PacketListener" ve "PacketAdapter" farklılıkları, addPacketListener() metodu, PacketType, paketleri dinleme gibi konular hakkında bilginiz yoksa bu kurstan bir şey anlamayabilirsiniz. Bu yüzden lütfen ilk makaleyi okuduğunuza emin olunuz. İlk kursa gitmek için bana tıkla!
Bu bölümde sunucunun oyuncuya gönderdiği paketleri veya oyununun sunucuya gönderdiği paketleri iptal etmeyi ve kendi paketlerimizi oluşturmayı öğreneceğiz. ProtocolLib bittikten sonra NMS'ler üzerinden devam edeceğiz.
Bölüm 1 : Paketleri İptal Etme
Sunucunuza gelişmiş bir sohbet koruması yazmak istediğinizi varsayalım. Bunun için oyuncunun sunucuya gönderdiği Chat paketini (serverbound) dinlememiz gerekmekte. Paketimizi wiki.vg/Protocol üzerinden kontrol edelim:
Paketimiz sadece tek bir "String" değeri içermektedir. Bu yüzden
container.getStrings().index(0);
ile String değerini almamız gerekmekte. Bu yüzden bunu şu şekilde yapabiliriz:
Java:
String message = container.getStrings().read(0);
Sonra bu String değerimiz kötü bir kelime içeriyor mu diye kontrol etmemiz gerekiyor. Bunu küçük bir if-else ile yapabiliriz:
Java:
if (message.contains("küfür") || message.contains("diğerKüfür")){
event.setCancelled(true); // Mesaj gönderimi iptal edildi
event.getPlayer().sendMessage("Küfür yasak!");
}
Bu konumuz String manipülasyonu olmadığı için detaylı küfür veya website yakalamayı anlatmıyorum. Yukarıda gönderdiğimiz mesajı iptal ettik. Kodumuzun son görünümü şu şekilde olacaktır:
Java:
protocolManager.addPacketListener(new PacketAdapter(this, ListenerPriority.LOW, PacketType.Play.Client.CHAT) {
@Override
public void onPacketReceiving(PacketEvent event) {
PacketContainer container = event.getPacket();
String message = container.getStrings().read(0);
if (message.contains("küfür") || message.contains("diğerKüfür")){
event.setCancelled(true);
event.getPlayer().sendMessage("Küfür yasak!");
}
}
});
Bölüm 2 : Paketler Oluşturma
Paket oluşturma işi, dinlemede yaptığımız işe çok benzemektedir. Sadece bu sefer değerleri "read" etmektense "write" edeceğiz. Şimdi sunucuda bir patlama efekti oluşturalım. Bu bir clientbound işlemdir. Çünkü sunucu, oyuncuya sunucuda patlama olduğunu bildirecek paketler göndermektedir. Bu yüzden wiki sayfamızın Play kısmından Clientbound paketleri inceliyoruz. Oradan Explosion paketii bulup inceliyoruz:
Bu kursu yazarken bilerek Explosion paketini ele aldım. Çünkü wikide koordinalar "Float" olarak verilmiş. Ancak biz bunları yazarken Double olarak yazmalıyız. Aksi taktirde bir hatayla karşı karşıya kalacağız. Pluginimizin onEnable() metoduna yeni bir "Command Executor" oluşturuyorum ve adan komutumuzun çalışması için gereken class'ı oluşturuyorum (TestPluginCommand).
Java:
getServer().getPluginCommand("boom").setExecutor(new TestPluginCommand());
Java:
public class TestPluginCommand implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
return false;
}
}
Ardından komutu kullanan kişinin oyuncu olduğunu doğrulamak için bir if-else kodu yazıyorum:
Java:
if (sender instanceof Player){
Player player = (Player) sender;
}
Sonra da ProtocolManager objemizi oluşturuyoruz:
ProtocolManager manager = ProtocolLibrary.getProtocolManager();
. Bu adımları tamamladıktan sonra oyuncunun baktığı bloğu almamız gerekiyor. Spigot bize getLineOfSight() metodu sağlamakta. Bu metot oyuncunun gözünden bir çizgi çekmekte ve o çizgi içerisindeki tüm blokları almakta. Bu metot iki adet değer almaktadır: @NotNull
public List<Block> getLineOfSight(@Nullable Set<Material> transparent, int maxDistance);
Biz burada transparent için "null" , maksimum görüş uzaklığımızı da 25 olarak belirleyeceğiz. Ardından bu aralıkta aldığımız blokları Java 8 ile gelen .stream() metodunu kullanarak filtreliyeceğiz. Son olarak bir forEach() döngüsü ile istediğimiz bloğa ulaşacağız. Eğer stream(), filter(), map() gibi fonksiyonları bilmiyorsanız daha fazla bilgi için "Java Doc"'lara bakabilirisiniz: https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html
Java:
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (sender instanceof Player){
Player player = (Player) sender;
ProtocolManager manager = ProtocolLibrary.getProtocolManager();
player.getLineOfSight(null,25).stream().filter(block -> block.getType() != Material.AIR).forEach(block -> {
});
}
return false;
}
Ardından bloğumuzun lokasyonunu
Location location = block.getLocation();
ile alıyoruz. Sonrasında bir PacketContainer oluşturuyoruz ancak bu sefer ProtocolManager objemizden createPacket(PacketType);
fonksiyonunu kullanıyoruz:
Java:
PacketContainer container = manager.createPacket(PacketType.Play.Server.EXPLOSION);
Ardından gerekli yerleri
.write(index, value)
şeklinde dolduruyoruz:
Java:
container.getDoubles().write(0,location.getX()); // X
container.getDoubles().write(1,location.getY()); // Y
container.getDoubles().write(2,location.getZ()); // Z
container.getFloat().write(0,5.0f); // Büyükük
container.getFloat().write(1,0.0f); // X ivmesi
container.getFloat().write(2,5.0f); // Y ivmesi
container.getFloat().write(3,0.0f); // Z ivmesi
Sonunda ise paketi oyuncuya gönderiyoruz:
Kod:
try {
manager.sendServerPacket(player,container);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
Eklentimizi çalıştırmadan önce yapmamız gereken son şey "plugin.yml" dosyasına "boom" komudunu eklemek olacaktır:
Kod:
commands:
boom:
description: Haha patlamalar goes brrr