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.

You'll want to define an API method for each "unit" your data, such as a String, int, ItemStack or a custom type like Home. These units will be wrapped in a Value, which will allow it to be accessed with Keys. There are various extensions of Value depending on which object will be represented, such as MapValue which provides the standard map operations, or MutableBoundedValue which can set limits on the upper and lower bound of the value (like integers). The bounds of the values are verified using a Comparator.

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.bisa berubah.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

:javadoc:`TipeToken`s digunakan oleh implementasi untuk melestarikan jenis nilai anda. Sponge menyediakan daftar panjang pra-dibangun toekn untuk API di:javadoc:TipeToken.

Jika anda perlu membuat sendiri, anda bisa melakukan ini dengan salah satu dari dua cara berikut:

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

Pendaftaran

Mendaftar anda DataManipulator memungkinkan untuk dapat diakses oleh Spons dan oleh plugin lain dengan cara yang umum. Permainan/plugin yang dapat membuat salinan data anda dan serialize/deserialize data anda tanpa referensi apapun dari kelas anda secara langsung.

Untuk mendaftar DataManipulator Sponge mempunyai DataRegistrasi#builder()`pembantu. ini akan membangun:javadoc:`DataRegistrasi dan secara otomatis mendaftarkannya.

Catatan

Karena sifat dari data, Kamu harus mendaftarkan DataManipulator selama inisialisasi - biasanya dengan mendengarkan :javadoc:`GamelnitializationEvent` seperti pada contoh dibawah ini, jika kamu mencoba untuk mendaftar DataManipulator setelah inisialisasi selesai pengecualian akan dilemparkan.

import org.spongepowered.api.event.game.state.GameInitializationEvent;
import org.spongepowered.api.data.DataRegistration;

import org.example.MyCustomData;
import org.example.ImmutableCustomData;
import org.example.CustomDataBuilder;

@Listener
public void onInit(GameInitializationEvent event) {
  DataRegistration.builder()
      .dataClass(MyCustomData.class)
      .immutableClass(ImmutableCustomData.class)
      .builder(new CustomDataBuilder())
      .manipulatorId("my-custom")
      .dataName("My Custom")
      .build();
}

Peringatan

Data that was serialized prior to 6.0.0, or data where you have changed the ID, will not be recognized unless registered with DataManager#registerLegacyManipulatorIds(String, DataRegistration). If registering a pre-6.0.0 DataManipulator the ID is taken from Class.getName(), such as com.example.MyCustomData.

Tipe tunggal

Single types require little implementation because much of the work has already been done in the AbstractSingleData type you extend from.

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

  • Boolean

  • Comparable

  • 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.

The following 3 methods must be defined on mutable manipulators:

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

In addition to the methods from the simple single types, you need to override the following methods:

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

Next, you'll want to register these so that the Keys-based system can reference them. To do this, implement either AbstractData#registerGettersAndSetters() or AbstractImmutableData#registerGetters() depending on whether the data is mutable or not.

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.