Özel DataManipulators

Özel verilerin temel kısmı :javadoc: DataManipulator dir. Bunu uygulamak için, önce özel verileriniz için ayrı bir API oluşturmak isteyip istemediğinize karar vermeniz gerekir. Genel olarak konuşmak gerekirse, uygulamanın API’sını (SpongeAPI gibi) ayırmak en iyisidir, ancak diğer geliştiriciler tarafından görülemeyecek olursa her ikisini de aynı sınıfa koyabilirsiniz.

Verilerinizin her “birimi” için bir `` String``, `` int``,: javadoc: ItemStack veya` Home` gibi özel bir tip gibi tanımlamak isteyeceksiniz. Bu birimler bir: javadoc: Değer ‘ile birleşir ve bu da: javadoc: Key`’i s ile erişilebilir. Hangi nesnenin temsil edileceğine bağlı olarak, “Değer” in çeşitli uzantıları vardır: javadoc: Standart harita işlemlerini sağlayan “MapValue” veya: üst ve alt sınırlara sınırlar koyabilen javadoc: BoundedComparableValue of: javadoc: Comparable nesneleri tamsayılar gibi.

Şimdi, uzatacağınız AbstractData türlerinden hangisiyse onu seçin. Sıfırdan uygulayabiliyorken, bu soyut tipler, gerekli yöntemleri uygulayarak yapılması gereken işin büyük bir kısmını kaldırır. Tam bir liste şu adreste bulunabilir org.spongepowered.api.data.manipulator.mutable.common. Her bir türü uygulama ayrıntıları için single-data-types`veya :ref:`compound-data-types bölümüne bakınız.

Değişken olan ve uygulayan iki farklı sınıf oluşturmanız gerekir DataManipulator soyut ve değişken, bir diğeri ise :javadoc:`ImmutableDataManipulator`sizin immutable soyut türünüzü uygulayan değişmez bir tür.

Not

Tüm veriler, değiştirilebilir ve değişmez sürümlere sahip olmalı, her ikisini de uygulamalısınız.

Her tür için şunları tanımlamanız gerekir DataManipulator#asImmutable()/ asMutable() yöntemler - varolan nesneleri başka bir sürüm için bir yapıcıya kopyalamak kadar basittir.

Değerler

Değer alıcı(lar)ınız bir değer döndürmelidir. Aşağıdaki örnekte :javadoc:`ValueFactory`yi elde ediyoruz. Bu, Sponge'un halihazırda uygulanmış ``Value`` nesnelerini kullanarak çok fazla şey kazandırır. Oluşturduğunuz değere bağlı olarak createMapValue,` createBoundedComparableValue` gibi farklı yöntemler çağırabilir.

Kod örneği: Bir değer olan “Getter“‘ı dahil etmek

import org.spongepowered.api.Sponge;
import org.spongepowered.api.data.value.ValueFactory;
import org.spongepowered.api.data.value.mutable.Value;

import org.spongepowered.cookbook.myhomes.data.home.Home;
import org.spongepowered.cookbook.myhomes.data.Keys;

@Override
protected Value<Home> defaultHome() {
    return Sponge.getRegistry().getValueFactory()
            .createValue(Keys.DEFAULT_HOME, getValue(), null);
}

Bunun yerine bir ImmutableDataManipulator, döndürülen Value üzerinde asImmutable() çağrısı yapılarak bir ImmutableValue döndürür. Değişken olmayan sürümde bunu (sınıf alanı gibi) önbelleğe almanızı öneririz.

Her bir Değer``in ayrıca :javadoc:`Anahtar` tanımlaması gerekir, örnekte ``Keys.DEFAULT_HOME olarak görülüyor. Değerlerinize benzer şekilde, değeriniz için bir Anahtar yaratmak için; makeXKey() yöntemlerinden birini kullanın KeyFactory.

Değerinizin ham type’ını ve Value``yu simgeleyen iki ayrı ``TypeToken okutmalısınız. Aynı zamanda DataQuery yolunu -bu ``Value``yu şifrelemek için en sık kullanılan yöntemdir- belirtmelisiniz. Çoğu katalog type’ında olduğu gibi isim ve benzersiz bir ID belirtmelisiniz. Bunların hepsini yaptığınızda ``Value``unuzda kullanabileceğiniz bir ``Key``iniz olacaktır.

** Kod örneği: Bir anahtar oluşturmak**

import org.spongepowered.api.data.DataQuery;
import org.spongepowered.api.data.key.Key;
import org.spongepowered.api.data.key.KeyFactory;
import org.spongepowered.api.data.value.mutable.Value;
import org.spongepowered.api.data.value.mutable.Value;

import com.google.common.reflect.TypeToken;

import org.spongepowered.cookbook.myhomes.data.home.Home;

public static final Key<Value<Home>> DEFAULT_HOME = KeyFactory.makeSingleKey(
        TypeToken.of(Home.class),
        new TypeToken<Value<Home>>() {},
        DataQuery.of("DefaultHome"), "myhomes:default_home", "Default Home");

Not

: javadoc: TypeToken s değerleri, değerlerin genel türünü korumak için sunucu uygulaması tarafından kullanılır. Bunlar iki yoldan biriyle oluşturulur:

  • Genel olmayan türler için, ``TypeToken.of (MyType.class)``kullan

  • Jenerik tipler için, TypeToken<MyGenericType<String>(){} bilinmeyen sınıfı oluşturabilirsiniz

Serileştirme

Verilerinizi serileştirilebilir hale getirebilmek için serializable’ı :javadoc:`DataHolder`config veya config dosyaları da uygulamanız gerekir :javadoc:`DataSerializable#toContainer() `. ``super.toContainer()`` çağrılmasını öneririz, çünkü bu sürüm aşağıdakilerden oluşacaktır DataSerializable#getContentVersion(). Seri hale getirilmiş verilerinizin formatında her değişiklik yapıldığında sürümü artırmanız ve geriye doğru uyumluluğa izin vermek için DataContentUpdaters kullanmanız gerekir.

Not

Bu, basit tek türler için gerekli değildir, hali hazırda toContainer() uygulanıyor

Kod Örneği: toContainer Uygulama

import org.spongepowered.api.data.DataContainer;

import org.spongepowered.cookbook.myhomes.data.Keys;

@Override
public DataContainer toContainer() {
    DataContainer container = super.toContainer();
    // This is the simplest, but use whatever structure you want!
    container.set(Keys.DEFAULT_HOME.getQuery(), this.defaultHome);
    container.set(Keys.HOMES, this.homes);

    return container;
}

Tek Tipler

Tek tipler, çok az uygulama gerektirir, çünkü işin büyük kısmı zaten uzantılı AbstractSingleData tipi içerisinde yapılmıştır.

“Basit” soyut türleri en kolay uygulanabilir ancak yalnızca aşağıdaki türlerle sınırlıdır:

  • Boolean

  • Comparable

  • Integer

  • Liste

  • Harita

  • CatalogType

  • Enum

Diğer tüm türler için, AbstractSingleData uzatarak özel bir tek tip uygulamanız gerekir. Bu sizin için en çok işi yapmaya devam ederken, istediğiniz tek tipte kendi tek verilerinizi tanımlamanıza izin verir.

Tüyo

Soyut uygulamalar, nesneyi yapıcıya kaydeder. Uygulamanızda,``getValue()`` ve `` getValueGetter() yöntemlerini çağırarak erişebilirsiniz.

Basit Tek Türler

Hemen hemen tüm çalışmalar basit soyut türlerle yapılır. Tek yapmanız gereken:

  • İlgili soyut türünü uzatın

  • verilerinizi, nesnenin kendisi ve varsayılan nesnesi (nesne boş ise) için olan Key’i oluşturucudan geçirin

AbstractBoundedComparableData (ve değiştirilemeyen eşdeğeri) ek olarak kontrol edilecek minimum ve maksimum değerleri ve ayrıca bir Comparator gerektirir.

Not

List ve Mapped tekil tipleri yerine ListData/MappedData``(ya da bunların immutable benzerlerini) tiplerini kullanmalısınız. Bu ayrıca ``DataManipulator üzerinde Map ve List benzeri etkileri kullanabileceğiniz metodları sağlar.

Değiştirilebilir manipluatörler üzerinde aşağıdaki 3 yöntem tanımlanmalıdır:

fill(DataHolder, MergeFunction), MergeFunction#merge() sonucunda DataHolder ile verilmiş olan objenizin verisini değiştirmelidir.

import org.spongepowered.api.data.DataHolder;
import org.spongepowered.api.data.merge.MergeFunction;

import org.spongepowered.cookbook.myhomes.data.friends.FriendsData;

import java.util.Optional;

@Override
public Optional<FriendsData> fill(DataHolder dataHolder, MergeFunction overlap) {
    FriendsData merged = overlap.merge(this, dataHolder.get(FriendsData.class).orElse(null));
    setValue(merged.friends().get());

    return Optional.of(this);
}

from(DataContainer), değerini container içindekiyle overwrite etmelidir ve kendine dönüt sağlamalıdır, aksi taktirde``Optional.empty()`` dönütü sağlayacaktır

import org.spongepowered.api.data.DataContainer;
import org.spongepowered.api.data.DataQuery;

import org.spongepowered.cookbook.myhomes.data.Keys;
import org.spongepowered.cookbook.myhomes.data.friends.FriendsData;
import org.spongepowered.cookbook.myhomes.data.friends.ImmutableFriendsData;

import com.google.common.collect.Maps;

import java.util.Optional;
import java.util.UUID;

@Override
public Optional<FriendsData> from(DataContainer container) {
    if(container.contains(Keys.FRIENDS)) {
        List<UUID> friends = container.getObjectList(Keys.FRIENDS.getQuery(), UUID.class).get();
        return Optional.of(setValue(friends));
    }

    return Optional.empty();
}

copy() isminden de anlaşılacağı üzere aynı verileri içeren bir kopyasını sağlamalıdır.

import org.spongepowered.cookbook.myhomes.data.friends.FriendsData;

@Override
public FriendsData copy() {
    return new FriendsDataImpl(getValue());
}

Özel Tek Türler

Buna ek olarak, aşağıdaki yöntemleri geçersiz kılmanız gerekir:

``getValueGetter()``a verinizi simgeleyen (yukarıyı kontrol edin) ``Value``yu okutmalısınız.

toContainer() verinizi simgeleyen (yukarıyı kontrol edin) DataContainer dönütlemelidir.

Bileşik türler

Tek türler yalnızca bir değeri desteklediğinde, “bileşik” türleri istediğiniz birçok değeri destekler. Bu, birden fazla nesne gruplanmış olduğunda yararlıdır FurnaceData. Bunun zayıf yönü, uygulamanın daha karmaşık olmasıdır.

Başlangıç olarak, verilerinizin sahip olacağı tüm Value çağırıcılarını oluşturun. Her değer için, daha sonra kullanacağınız raw nesnesini almak ve ayarlamak için bir yöntem oluşturun. Değişken olmayan veriler için yalnızca alıcılar gereklidir.

İşlemleri Kaydet

Sonra, bunları kaydetmek isteyeceksiniz ki Keys-based sistemi onlara referans verebilsin. Bunu yapmak için aşağıdakilerden birini uygulayın; Verilerin değiştirilebilir olup olmadığına bağlı olarak DataManipulator#registerGettersAndSetters() veya ImmutableDataManipulator#registerGetters() çağırın.

Herhangi bir işlem için aramanız gereken:

  • registerKeyValue(Key, Supplier) verilen key’in alıcısı ``Value``yu simgeler

  • registerFieldGetter(Key, Supplier), yukarıda belirlenmiş ham obje için getter metodunu simgeler

  • registerFieldSetter(Key, Consumer), eğer mutable alternatifini kullanıyorsanız yukarıdaki setter metodunu simgeler

Kolay Suplier ve Consumer fonksiyonları için Java 8’in :: sözdizimini öneriyoruz.

Örnek Kod: Getter’ların ve Setter’ların Kullanımı

import org.spongepowered.cookbook.myhomes.data.Keys

// registerGetters() for immutable implementation
@Override
protected void registerGettersAndSetters() {
    registerKeyValue(Keys.DEFAULT_HOME, this::defaultHome);
    registerKeyValue(Keys.HOMES, this::homes);

    registerFieldGetter(Keys.DEFAULT_HOME, this::getDefaultHome);
    registerFieldGetter(Keys.HOMES, this::getHomes);

    // Only on mutable implementation
    registerFieldSetter(Keys.DEFAULT_HOME, this::setDefaultHome);
    registerFieldSetter(Keys.HOMES, this::setHomes);
}

fill(DataHolder, MergeFunction) ve from(DataContainer), tekil veriler için olan uygulamalara benzerler, fakat farklı olarak bütün verilerinizi yüklerler.