Custom DataManipulator

Bagian inti dari data khusus adalah DataManipulator. Untuk menerapkannya, anda harus terlebih dahulu memutuskan jika anda ingin membuat terpisah API untuk data kustom anda. Pada umumnya hal terbaik untuk memisahkan API dari pelaksanaan (sebagai SpongeAPI tidak), tetapi jika itu tidak akan terlihat oleh pengembang lain maka anda hanya dapat menempatkan keduanya di kelas yang sama.

Anda akan menginginkan untuk menetapkan sebuah metode API untuk setiap "unit" data anda, seperti sebuah String, int, :javadoc:`ItemStack`atau sebuah tipe kustom seperti ``Home``. Unit-unit ini akan dibungkus dalam sebuah :javadoc: Value, dimana akan mengizinkannya untuk diakses dengan Keys. Ada beberapa variasi ekstensi dari Value tergantung pada objek mana yang akan diwakilkan, seperti MapValue dimana menyediakan peta operasi standar, atau BoundedComparableValue yang dapat menyesuaikan pada batas atas dan bawah dari sebuah Comparable objek seperti bilangan bulat.

Sekarang, pilih yang mana dari AbstractData jenis anda akan memperluas. Sementara anda bisa menerapkan dari awal, ini abstrak jenis menghapus banyak pekerjaan yang perlu dilakukan untuk menerapkan metode yang diperlukan. Daftar lengkap dapat ditemukan di org.spongepowered.api.data.manipulator.bisaberubah.umum. Lihat baik satu-data-jenis atau senyawa-tipe data di bawah untuk rincian pelaksanaan masing-masing jenis.

Anda harus membuat dua kelas yang berbeda - satu yang bisa berubah dan mengimplementasikan DataManipulator dan anda tipe abstrak, dan berubah versi yang mengimplementasikan ImmutableDataManipulator dan berubah tipe abstrak.

Catatan

Semua data harus memiliki versi yang bisa berubah dan tidak berubah, Anda harus menerapkan keduanya.

Untuk semua jenis, anda akan perlu untuk menentukan DataManipulator#asImmutable()/ asMutable() metode ini adalah yang sederhana seperti menyalin benda-benda yang ada menjadi sebuah konstruktor untuk versi alternatif.

Nilai

Pengambil nilai anda(s) perlu mengembalikan nilai tersebut. Seperti contoh dibawah, kami mendapatkan:javadoc:nilai tetap. Ini dapat menyelamatkan banyak jenis yang menggunakan Sponge's yang telah melaksanakan objek``nilai``. Baegantung pada nilai yang anda buat disana seperti kaedah yang berbeda yang dipanggil seperti``createMapValue``, createBoundedComprarableValue, dan lai-lain.

Contoh Kode: Melaksanakan Nilai Gatter

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);
}

Perhatikan bahwa ImmutableDataManipulator malah akan kembali ImmutableValue, dengan menyebut asImmutable() pada kembali Nilai. Kami merekomendasikan bahwa anda cache ini (seperti dengan kelas bidang) dalam berubah versi.

Setiap``nilai``juga memerlukan :javadoc:`kunci` untuk mengenal secara pasti, bisa dilihat dari contoh``kunci.DEFAULT_RUMAH``. sama untuk nilai, kamu menggunakan satu kaedah``makeXkey()``dalam:javadoc:KeyFactory`untuk membuat ``kunci` pada nilai anda.

Anda perlu lulus untuk satu TipeToken mewakili nilai *mentah*anda, dan satu TipeToken mewakili``nilai``. Kamu juga perlu menyediakan :javadoc:`DataPertanyaan` jalan - ini yang paling biasa dugunakan untuk seri Nilai. seperti mana dengan jenis katalog anda juga harus menyediakan ID unik dan nama. Masukkan semua sama-sama dan anda mempunyai kunci yang kamu boleh gunakan dalam Nilais.

Contoh Kode: Membuat Kunci

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");

Catatan

TypeTokens digunakan oleh implementasi server untuk mempertahankan tipe umum dari nilai anda. Mereka diciptakan dalam satu dari dua cara:

  • Untuk jenis bebas-umum, menggunakan TypeToken.of(Mytype.class)

  • Untuk jenis generik, Membuat kelas anonim dengan TypeToken<MyGenericType<String>>(){}

Serialisasi

Untuk membuat data anda:doc:serializable <../serilizable> to DataHolderor atau config file, anda juga harus menerapkan:javadoc:DataSerializable#toContainer(). Kami menyarankan memanggil super.toContainer() seperti ini kan termasuk versi dari:javadoc:DataSerializable#getContentVersion(). Kamu harus meningkat setiap kali perubahan yang dibuat ke format data serial, dan menggunakan :ref: konten-perbarui agar mundur kompatibilitas.

Catatan

Ini tidak diperlukan untuk jenis tunggal yang mudah, seperti yang telah dilakakukan toContainer()

Contoh Kode: Melaksanakan toContainer

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;
}

Tipe tunggal

Jenis tunggal memerlukan sedikit implementasi karena sabagian besar pekerjaan telah dilakukan pada jenis``AbstractSingleData`` jenis yang kamu perpanjang.

Jenis abstrak ''sederhana'' adalah yang termudah untuk diterapkan, tetapi dibatasi pada jenis dibawah ini:

  • Boolean

  • Sebanding

  • Bilangan

  • Daftar

  • Skema

  • CatalogType

  • Enum

Untuk semua jenis lain anda harus menerapkan kebiasaan satu jenis dengan memperpanjang AbstractSingleData. Hal ini memungkinkan anda untuk menentukan sendiri data tunggal dengan apapun jenis yang anda inginkan, sementara masih melakukan sebagian besar pekerjaan untuk anda.

Tip

Impementasi abstrak menyimpan objek untuk anda dalam konstruktor. Anda dapat mengaksesnya dalam penerapan dengan memanggil metode getValue()``dan``gerValue().

Sederhana Satu Jenis

Hampir semua pekerjaan dilakukan untuk anda dengan jenis abstrak sederhana. Yang anda butuhkan untuk melakukannya adalah:

  • Perluas jenis abstrak yang relavan

  • melewati kunci untuk data anda, Objek itu sendri dan objek defauft (jika objek null) di konstruktor

AbstractBoundedComparableData (dan sama abadi dengqan) selain itu memerlukan nilai-nilai minimum dan maksimum yang akan diperiksa, :javadoc:`Komperator`.

Catatan

Daftar and dipeta satu jenis sebaliknya harus menerapkan ListData / MappedData (atau sama abadi). Hal ini menambah tambahan metode untuk memungkinkan peta-like/daftar-seperti perilaku langsung pada DataManipulator.

3 metode berikut harus dedifenisikan pada manipulator yang bisa berubah:

fill(DataHolder, MergeFunction) seharusnya menggantikan data pada objek dengan DataHolder yang diberikan, dengan menggunakan hasil dari MergeFunction#merge().

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) seharusnya menimpa nilainya dengan yang ada di dalam container dan mengembalikan nilainya sendiri, jika tidak maka mengembalikan nilai Optional.empty()

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() seharusnya, seperti namanya, mengembalikan salinan dari salinan itu sendiri dengan data yang sama.

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

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

Kustom Jenis Tunggal

Selain itu, anda perlu mengganti metitode berikut:

getValueGetter() seharusnya melalui Value yang mewakili data anda (lihat di atas).

`` toContainer () `` harus mengembalikan DataContainer` yang mewakili data Anda (lihat di atas).

Gaya majemuk

Sedangkan jenis tunggal hanya mendukung satu nilai, "senyawa" jenis dukungan namun banyak nilai-nilai yang anda inginkan. Hal ini berguna ketika beberapa objek dikelompokkan, seperti FurnaceData. Sisi negatifnya, bagaimanapun, adalah bahwa mereka yang lebih kompleks untuk diimplementasikan.

Untuk memulai dengannya, buatlah semua getter Value yang data anda akan miliki. Untuk setiap nilainya, buatlah metode untuk mengambil dan mengatur objek raw, yang akan anda gunakan nanti. Untuk data tetap, hanya getter yang diperlukan.

Mendaftarkan Nilai

Selanjutnya, anda ingin mendaftarkan ini semua agar sistem dasar-Keys dapat mereferensikan itu semua. Untuk melakukannya, implementasikan salah satu DataManipulator#registerGettersAndSetters() atau ImmutableDataManipulator#registerGetters() yang bergantung pada apakah data tersebut tidak tetap atau tetap.

Untuk setiap nilai yang perlu anda hubungi:

  • `` registerKeyValue (Key, Supplier) `` merujuk pada pengambil nilai `` Value` untuk kunci yang diberikan

  • `` registerFieldGetter (Key, Supplier) `` merujuk metode pengambil untuk objek * mentah * yang didefinisikan di atas

  • `` registerFieldSetter (Kunci, Konsumen) `` merujuk metode penyetel di atas jika Anda menerapkan versi yang dapat diubah

Sebaiknya gunakan sintaks Java `` `` `` untuk fungsi `` Pemasok``````````````````````````````.

Contoh Kode: Melaksanakan Nilai Gatter

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);
}

`` isi (DataHolder, MergeFunction) `` dan `` dari (DataContainer) `` mirip dengan implementasi untuk satu data, namun memuat semua nilai Anda.