Menerapkan datamanipulator
Ini merupakan petunjuk bagi para kontributor yang ingin membantu pelaksanaan Data API dengan membuat DataManipulators. Daftar DataManipulators yang telah terupdate yang akan dijalankan bisa di temukan di 'SpongeCommon Issue #8 <https://github.com/SpongePowered/SpongeCommon/issues/8>'_.
Untuk menerapkan ' ' datamanipulator ' ' langkah-langkah ini harus diikuti:
Terapkan ' ' datamanipulator ' ' sendiri
Terapkan ' ' datamanipulator ' '
Bila langkah-langkah ini telah selesai, berikut juga harus dilakukan:
Daftarkan
kunci
di dalamKunciDaftar
Terapkan ' ' datamanipulator ' '
Jalankan
NilaiProcessor
untuk tiap nilai yang telah digambarkan olehDataManipulator
Daftarkan semuanya kedalam
DaftarSerialSpone
Jika data berlaku untuk blok, beberapa metode juga harus dicampur ke blok.
Catatan
Pastikan anda mengukiti ../petunjuk kami.
1. Terapkan Datamanipulator
Konvensi penamaan untuk DataManipulator implementasi adalah nama interface yang diawali dengan "Sponge". Jadi, untuk melaksanakan HealthData antarmuka, kita membuat sebuah class bernama SpongeHealthData dalam paket yang sesuai. Untuk melaksanakan DataManipulator pertama memilikinya memperpanjang sesuai kelas abstrak dari org.spongepowered.umum.data.manipulator.bisa berubah.umum paket. Yang paling umum ada AbstractData tapi ada juga abstraksi yang mengurangi kode boilerplate bahkan lebih untuk beberapa kasus khusus seperti DataManipulators hanya dapat berisi satu nilai.
public class SpongeHealthData extends AbstractData<HealthData, ImmutableHealthData> implements HealthData {
[...]
}
Ada dua jenis argumen untuk AbstractData kelas. Yang pertama adalah interface yang diimplementasikan oleh kelas ini, yang kedua adalah antarmuka yang dilaksanakan oleh yang bersangkutan, ImmutableDataManipulator.
Pembuatnya
Dalam kebanyakan kasus saat menerapkan abstrak ' ' Datamanipulator ' ' kamu harus memiliki dua konstruktor:
Satu tanpa argumen (tidak-args) yang akan memanggil konstruktor kedua dengan "gagal" nilai
Konstruktor kedua yang mengambil semua nilai yang didukungnya.
Konstruktor kedua harus
lakukan panggilan ke
AbstrakData
konstruktor, melewati tahapan rujukan untuk pelaksanaan antar muka.pastikan nilai yang dilewatkan benar
hubungi
registerGettersAndSetters()
metode
import static com.google.common.base.Preconditions.checkArgument;
public class SpongeHealthData {
public SpongeHealthData() {
this(DataConstants.DEFAULT_HEALTH, DataConstants.DEFAULT_HEALTH);
}
public SpongeHealthData(double currentHealth, double maxHealth) {
super(HealthData.class);
checkArgument(currentHealth >= DataConstants.MINIMUM_HEALTH && currentHealth <= (double) Float.MAX_VALUE);
checkArgument(maxHealth >= DataConstants.MINIMUM_HEALTH && maxHealth <= (double) Float.MAX_VALUE);
this.currentHealth = currentHealth;
this.maximumHealth = maxHealth;
this.registerGettersAndSetters();
}
...
}
Karena kita tahu bahwa saat ini kesehatan dan kesehatan yang maksimal yang dibatasi nilai-nilai, kita perlu memastikan tidak ada nilai di luar batas-batas ini dapat dilewatkan. Untuk mencapai hal ini kita menggunakan jambu biji Prasyarat yang kita impor diperlukan metode.
Catatan
Tidak pernah menggunakan apa yang disebut sihir nilai-nilai (sewenang-wenang angka, boolean dll) dalam kode anda. Sebaliknya, cari org.spongepowered.umum.data.util.DataConstants kelas dan menggunakan pas konstan atau membuat satu, jika diperlukan.
Para pengakses ditentukan oleh Antarmuka
Antarmuka kami menerapkan menentukan beberapa metode untuk mengakses Nilai benda-benda. Untuk HealthData, mereka adalah kesehatan() dan maxHealth(). Setiap panggilan untuk orang-orang harus menghasilkan sebuah Nilai.
public MutableBoundedValue<Double> health() {
return SpongeValueFactory.boundedBuilder(Keys.HEALTH)
.minimum(DataConstants.MINIMUM_HEALTH)
.maximum(this.maximumHealth)
.defaultValue(this.maximumHealth)
.actualValue(this.currentHealth)
.build();
}
Tip
Karena Double
adalah Comparable
, kita tidak perlu secara eksplisit menentukan komparator.
Jika tidak ada nilai yang telah di tentukan, panggil get()
pada Value
mengembalikan nilai default.
Penyalinan dan serialisasi
Dua metode copy() dan asImmutable() tidak banyak pekerjaan yang harus melaksanakan. Untuk investasi anda hanya perlu untuk kembali bisa berubah atau berubah data manipulator masing-masing, yang berisi data yang sama sebagai contoh saat ini.
Metode toContainer() digunakan untuk serialisasi tujuan. Menggunakan MemoryDataContainer sebagai hasil dan menerapkan nilai-nilai yang disimpan dalam contoh ini. DataContainer pada dasarnya adalah sebuah peta pemetaan DataQuerys untuk nilai-nilai. Sejak a Kunci selalu berisi sesuai DataQuery, hanya digunakan oleh orang-orang yang lewat Kunci ini diatas.
public DataContainer toContainer() {
return new MemoryDataContainer()
.set(Keys.HEALTH, this.currentHealth)
.set(Keys.MAX_HEALTH, this.maximumHealth);
}
registerGettersAndSetters()
Metode toContainer() digunakan untuk serialisasi tujuan. Menggunakan MemoryDataContainer sebagai hasil dan menerapkan nilai-nilai yang disimpan dalam contoh ini. DataContainer pada dasarnya adalah sebuah peta pemetaan DataQuerys untuk nilai-nilai. Sejak a Kunci selalu berisi sesuai DataQuery, hanya digunakan oleh orang-orang yang lewat Kunci ini diatas:
daftarkan
Supplier
untuk langsung mendapatkan nilaidaftarkan
Consumer
untuk langsung mengeset nilaidaftarkan
Supplier<Value>
untuk mendapatkanNilai
yang berubah-ubah
Supplier
dan Consumer
merupakan penghubung fungsional, sehingga Java 8 Lambdas dapat digunakan.
private void setCurrentHealthIfValid(double value) {
if (value >= DataConstants.MINIMUM_HEALTH && value <= (double) Float.MAX_VALUE) {
this.currentHealth = value;
} else {
throw new IllegalArgumentException("Invalid value for current health");
}
}
private void setMaximumHealthIfValid(double value) {
if (value >= DataConstants.MINIMUM_HEALTH && value <= (double) Float.MAX_VALUE) {
this.maximumHealth = value;
} else {
throw new IllegalArgumentException("Invalid value for maximum health");
}
}
private void registerGettersAndSetters() {
registerFieldGetter(Keys.HEALTH, () -> SpongeHealthData.this.currentHealth);
registerFieldSetter(Keys.HEALTH, SpongeHealthData.this::setCurrentHealthIfValid);
registerKeyValue(Keys.HEALTH, SpongeHealthData.this::health);
registerFieldGetter(Keys.MAX_HEALTH, () -> SpongeHealthData.this.maximumHealth);
registerFieldSetter(Keys.MAX_HEALTH, SpongeHealthData.this::setMaximumHealthIfValid);
registerKeyValue(Keys.MAX_HEALTH, SpongeHealthData.this::maxHealth);
}
Konsumen terdaftar sebagai bidang setter harus melakukan yang memadai pemeriksaan untuk memastikan diberikan nilai yang berlaku. Hal ini berlaku terutama untuk DataHolder`s yang tidak bisa menerima nilai-nilai negatif. Jika nilai yang tidak valid, `IllegalArgumentException harus dibuang.
Tip
Validitas kriteria bagi mereka setter adalah sama seperti untuk masing-masing Nilai objek, sehingga anda bisa mendelegasikan validitas cek ke call of ini.kesehatan().set() dan set ini.currentHealth = nilai jika baris pertama tidak memiliki pengecualian dilemparkan belum.
Itu dia, ' ' Datamanipulator ' ' harus dilakukan sekarang.
2. Terapkan ImmutableDataManipulator
Menjalankan ImmutableDataManipulator
sama dengan menjalankan data yang bisa berubah.
Satu-satunya perbedaan adalah:
Nama kelas dibentuk oleh awalan nama
DataManipulator
s yang bisa dapat diubah denganImmutableSponge
Mewarisi dari
ImmutableAbstractData
sebagai gantinyaGanti dari
registerGettersAndSetters()
, metode ini disebutregisterGetters()
Ketika menciptakan ImmutableDataHolders atau ImmutableValues, memeriksa apakah itu masuk akal untuk menggunakan ImmutableDataCachingUtil. Misalnya jika anda memiliki WetData yang berisi tidak lebih dari sebuah boolean, itu lebih layak untuk mempertahankan hanya dua cache contoh ImmutableWetData - satu untuk setiap kemungkinan nilai. Untuk manipulator dan nilai-nilai dengan banyak nilai yang mungkin (seperti SignData) namun, caching ini terbukti terlalu mahal.
Tip
Anda harus mendeklarasikan bagian dari ImmutableDataManipulator
sebagai final
untuk mencegah perubahan yang tidak disengaja.
3. Daftarkan Key di KeyRegistry
Langkah berikutnya adalah untuk mendaftar anda Kuncis KeyRegistry. Untuk melakukannya, cari org.spongepowered.umum.data.kunci.KeyRegistry kelas dan menemukan statis generateKeyMap() fungsi. Ada tambahkan baris untuk mendaftar (dan membuat) digunakan tombol.
keyMap.put("health"), makeSingleKey(Double.class, MutableBoundedValue.class, of("Health")));
keyMap.put("max_health", makeSingleKey(Double.class, MutableBoundedValue.class, of("MaxHealth")));
Peta peta string untuk Kuncis. String yang digunakan harus sesuai nama konstan dari Kunci utilitas kelas dalam huruf kecil. Kunci itu sendiri dibuat oleh salah satu metode statis yang diberikan oleh KeyFactory, dalam kebanyakan kasus makeSingleKey. makeSingleKey membutuhkan pertama kelas acuan bagi data yang mendasar, yang dalam kasus kita adalah "Ganda", maka kelas referensi untuk Value type yang digunakan. Argumen ketiga adalah DataQuery digunakan untuk serialisasi. Hal ini dibuat dari..... diimpor DataQuery.() metode menerima string. String ini juga harus konstan nama, dilucuti dari garis bawah dan kapitalisasi berubah ke atas unta kasus.
4. Terapkan DataProcessors
Berikutnya adalah DataProcessor. DataProcessor berfungsi sebagai jembatan antara kita DataManipulator dan Minecraft benda-benda. Setiap kali ada data yang diminta atau ditawarkan untuk DataHolders yang ada di Minecraft Vanilla, panggilan-panggilan itu berakhir menjadi didelegasikan ke DataProcessor atau ValueProcessor.
Untuk nama anda, anda harus menggunakan nama DataManipulator
penghubung dan menambahkan Processor
. Untuk HealthData
kami membuat HealthDataProcessor
.
Dalam rangka untuk mengurangi kode boilerplate, DataProcessor harus mewarisi dari yang sesuai kelas abstrak dalam org.spongepowered.umum.data.prosesor.umum paket. Karena kesehatan hanya dapat hadir pada badan-badan tertentu, kita dapat menggunakan AbstractEntityDataProcessor yang khusus ditujukan pada Entitas yang didasarkan pada net.minecraft.entitas.Entitas. AbstractEntitySingleDataProcessor akan memerlukan waktu kurang pelaksanaan pekerjaan, tetapi tidak dapat digunakan sebagai HealthData berisi lebih dari satu nilai.
public class HealthDataProcessor extends AbstractEntityDataProcessor<EntityLivingBase, HealthData, ImmutableHealthData> {
public HealthDataProcessor() {
super(EntityLivingBase.class);
}
[...]
}
Tergantung pada abstraksi yang anda gunakan, metode yang anda harus menerapkan mungkin sangat berbeda, tergantung pada seberapa jauh pelaksanaan pekerjaan sudah bisa dilakukan di kelas abstrak. Umumnya, metode-metode yang dapat dikategorikan.
Tip
Hal ini dimungkinkan untuk membuat beberapa DataProcessors untuk data yang sama. Jika sangat berbeda DataHolders harus didukung (misalnya kedua TileEntity dan pencocokan ItemStack), mungkin akan bermanfaat untuk membuat satu prosesor untuk setiap jenis DataHolder dalam rangka untuk membuat penuh penggunaan abstraksi yang disediakan. Pastikan anda mengikuti paket struktur untuk barang-barang, tileentities dan badan.
Metode validasi
Selalu kembalikan nilai boolean. Jika metode tersebut disebut supports()
metode tersebut seharusnya melakukan pengecekan umum jika target yang diberikan biasanya mendukung jenis data yang ditangani oleh DataProcessor
.
Untuk HealthDataProcessor
kami Support()
dijalankan oleh AbstractEntityDataProcessor
. Per default, hal tersebut akan kembali benar jika argumen yang diberikan merupakan turunan dari kelas yang telah ditentukan saat memanggil super()
konstruktor.
Sebagai gantinya, kita diminta untuk menyediakan metode doesDataExist()
. Karena abstraksi tidak tahu bagaimana mendapatkan data, hal tersebut membiarkan fungsi ini dijalankan. Seperti nama nya, metode tersebut harus memeriksa apakah data sudah ada pada target yang didukung. Untuk HealthDataProcessor
, hal ini selalu kembali benar, karena setiap entitas yang hidup selalu memiliki kesehatan.
protected boolean doesDataExist(EntityLivingBase entity) {
return true;
}
Metode Pengaturan
Metode pengaturan menerima DataHolder
dari beberapa jenis dan beberapa data yang harus dijalankan padanya, jika memungkinkan.
Antarmuka DataProcessor
mendefinisikan sebuah set()
metode menerima``DataHolder`` dan DataManipulator
yang mengembalikan DataTransactionResult
. Bergantung pada kelas abstraksi yang digunakan, beberapa fungsi yang diperlukan mungkin sudah diterapkan.
Pada kasus ini, AbstractEntitydataProcessor
mengurus sebagian besar proses dan hanya membutuhkan sebuah metode untuk mengeset sebagian nilai agar kembali true
jika metode tersebut sukses dijalankan dan false
jika tidak sukses. Semua pengecekan jika DataHolder
mendukung Data
akan ditangani, kelas abstrak hanya akan memberikan peta tiap Key
dari DataManipulator
ke nilainya dan kemudian menyusun DataTransactionResult
tergantung apakah operasi berhasi dijalankan atau tidak.
protected boolean set(EntityLivingBase entity, Map<Key<?>, Object> keyValues) {
entity.getEntityAttribute(SharedMonsterAttributes.maxHealth)
.setBaseValue(((Double) keyValues.get(Keys.MAX_HEALTH)).floatValue());
entity.setHealth(((Double) keyValues.get(Keys.HEALTH)).floatValue());
return true;
}
Tip
Untuk memahami DataTransactionResult
s, periksa :doc: sesuai halaman dokumen <../../plugin/data/transactions>` dan kembali ke DataTransactionResult.Builder docs untuk membuatnya.
Peringatan
Terutama saat bekerja dengan ItemStack
s kemungkinan anda harus berurusam dengan NBTTagCompound
s secara langsung. Banyak kunci NBT sudah didefinisikan sebagai ketetapan di kelas org.spongepowered.common.data.util.NbtDataUtil
. Jika kunci yang anda butuhkan tidak ada disana, anda harus menambahkannya untuk menghindari 'magic values' didalam kodenya.
Metode penghapusan
Metode remove()
mencoba untuk menghapus data dari DataHolder
dan mengembalikan DataTransactionResult
.
Penghapusan tidak diabstraksikan dalam abstrak DataProcessor
karena abstraksi tidak memiliki cara untuk mengetahui apakah data selalu ada pada DataHolder
yang kompatibel (seperti WetData
atau HealthData
) atau jika mungkin atau mungkin tidak hadir (seperti LoreData
). Jika data selalu ada, hapus()
harus selalu gagal. Jika mungkin atau mungkin tidak ada, hapus()
harus menghapusnya. Dalam kasus tersebut, metode doesDataExist()
harus diganti.
Karena entitas hidup selalu memiliki kesehatan, HealthData
selalu hadir dan karena itu tidak didukung. Oleh karena itu kami hanya mengembalikan failNoData()
dan tidak mengganti metode doesDataExist()
.
public DataTransactionResult remove(DataHolder dataHolder) {
return DataTransactionBuilder.failNoData();
}
Metode Getter
Metode getter mendapatkan data dari DataHolder
dan mengembalikan``DataManipulator`` opsional. Antarmuka DataProcessor
menentukan metode dari()
dan createFrom()
, perbedaannya adalah bahwa dari()
akan kembali Opsional.empty()
jika dudukan data kompatibel, namun saat ini tidak berisi data, sementara createFrom()
akan memberikan DataManipulator
memegang nilai bawaan dalam kasus itu.
Sekali lagi, AbstractEntityDataProcessor
akan menyediakan sebagian besar pengerjaan untuk prosess ini dan hanya membutuhkan satu metode untuk mendapatkan nilai sebenarnya yang tersedia di DataHolder
. Metode ini hanya di butuhkan setelah supports()
dan doesDataExist()
keduanya telah kembali benar, artinya metode tersebut bekerja dengan anggapan bahwa data tersedia.
Peringatan
Jika data mungkin tidak selalu ada pada target DataHolder
, seperti jika fungsi remove()
mungkin berhasil dijalankan (lihat diatas), hal ini menjadi sangat penting bahwa anda mengganti metode doesDataExist()
sehingga datanya kembali benar
ketika data disajikan dan salah
jika tidak.
protected Map<Key<?>, ?> getValues(EntityLivingBase entity) {
final double health = entity.getHealth();
final double maxHealth = entity.getMaxHealth();
return ImmutableMap.<Key<?>, Object>of(Keys.HEALTH, health, Keys.MAX_HEALTH, maxHealth);
}
Metode penyaringan
Metode pengisian berbeda dari metode getter ketika menerima DataManipulator
untuk diisi dengan nilai-nilai. Nilai-nilai tersebut bisa datang dari DataHolder
atau harus diserialkan kembali dari DataContainer
. Metode ini mengembalikan Optional.empty()
jika DataHolder
tidak sesuai.
AbstractEntityDataProcessor
telah menangani pengisian dari DataHolders
dengan menciptakan sebuah DataManipulator
dari pemegang dan kemudian menyatukannya dengan manipulator yang tersedia, tetapi serialisasi DataContainer
tidak dapat disediakan.
public Optional<HealthData> fill(DataContainer container, HealthData healthData) {
final Optional<Double> health = container.getDouble(Keys.HEALTH.getQuery());
final Optional<Double> maxHealth = container.getDouble(Keys.MAX_HEALTH.getQuery());
if (health.isPresent() && maxHealth.isPresent()) {
healthData.set(Keys.HEALTH, health.get());
healthData.set(Keys.MAX_HEALTH, maxHealth.get());
return Optional.of(healthData);
}
return Optional.empty();
}
Metode fill()
adalah untuk mengembalikan sebuah Optional
dari healthData yang diubah, jika dan hanya jika semua data yang dibutuhkan dapat diambil dari DataContainer
.
Metode lain
Tergantung pada abstract superclass yang digunakan, beberapa metode lain mungkin akan di butuhkan. Sebagai contoh, AbstractentityDataProcessor
perlu membuat DataManipulator
secara instan di beberapa titik. Hal ini tidak bisa di lakukan karena metode tersebut tidak mengetahui kelompok pelaksana juga tidak mengetahui konstruktor yang akan di gunakan. Oleh sebab itu metode ini akan menggunakan fungsi abstrak yang harus disediakan oleh pelaksana akhir. Hal ini hanya membuat DataManipulator
dengan data bawaan.
Jika anda menjalankan DataManipulator
anda sesuai dengan yang di rekomendasikan, anda hanya perlu menggunakan no-args konstruktor.
protected HealthData createManipulator() {
return new SpongeHealthData();
}
5. Terapkan ValueProcessors
Tidak hanya DataManipulator
yang mungkin di tawarkan kepada DataHolder
, tetapi juga kelengkapan Value
dengan sendiri nya. Untuk itu, anda harus menyediakan minimal satu ValueProcessor
untuk setiap Key
yang ada di DataManipulator
anda. Sebuah ValueProcessor
dinamai mengikuti nama tetap setiap Key
di dalam kelompok Keys
dengan bentuk yang sama dengan DataQuery
. Nama tetap tersebut dihilangkan garis bawah, digunakan dalam bentuk huruf besar dan di gabungkan dengan ValueProcessor
.
ValueProcessor
harus selalu di ambil dari AbstractSpongeValueProcessor
, yang akan memproses sebagian pengecekan Support()
sesuai dengan jenis DataHolder
. Untuk Key.HEALTH
, kita akan membuat dan mengkonstruk HealthValueProcessor
sebagai berikut.
public class HealthValueProcessor extends AbstractSpongeValueProcessor<EntityLivingBase, Double,
MutableBoundedValue<Double> {
public HealthValueProcessor() {
super(EntityLivingBase.class, Keys.HEALTH);
}
[...]
}
Sekarang AbstractSpongeValueProcessor
akan menggantikan kita dari keharusan mengecek apakah nilai telah didukung. Hal ini akan di asumsikan telah didukung jika target ValueContainer
adalah jenis EntityLivingBase
.
Tip
Untuk lebih memudahkan pengendalian terhadap objek EntityLivingBase
yang telah didukung, metode support(EntityLivingBase)
bisa diganti.
Sekali lagi, kebanyakan proses telah dilakukan oleh bagian abstraksi. Kita hanya perlu menjalankan dua metode pembantu untuk membuat value
dan mitra tetapnya dan tiga metode untuk mendapatkan, mengatur dan menghapus data.
protected MutableBoundedValue<Double> constructValue(Double value) {
return SpongeValueFactory.boundedBuilder(Keys.HEALTH)
.minimum(DataConstants.MINIMUM_HEALTH)
.maximum((double) Float.MAX_VALUE)
.defaultValue(DataConstants.DEFAULT_HEALTH)
.actualValue(value)
.build();
}
protected ImmutableValue<Double> constructImmutableValue(Double value) {
return constructValue(value).asImmutable();
}
protected Optional<Double> getVal(EntityLivingBase container) {
return Optional.of((double) container.getHealth());
}
Dikarenakan tidak mungkin sebuah EntityLivingBase
tidak memiliki kesehatan, metode ini tidak akan pernah kembali ke Optional.empty()
.
protected boolean set(EntityLivingBase container, Double value) {
if (value >= DataConstants.MINIMUM_HEALTH && value <= (double) Float.MAX_VALUE) {
container.setHealth(value.floatValue());
return true;
}
return false;
}
Metode set()
akan mengembalikan nilai boolean yang akan mengindikasikan apakah nilai dapat berhasil diatur. Melakukan proses ini akan menolak nilai di luar batas-batas yang telah digunakan didalam metode konstruksi nilai kami di atas.
public DataTransactionResult removeFrom(ValueContainer<?> container) {
return DataTransactionBuilder.failNoData();
}
Karena data dijamin selalu hadirkan, usaha untuk menghapusnya selalu gagal.
6. Daftar prosesor
Agar Sponge dapat menggunakan manipulator dan prosesor kami, kita perlu mendaftarkan nya. Proses ini di lakukan di kelas org.spongepowered.common.data.SpongeSerializationRegistry
. Dalam metode setupSerialization
ada dua blok besar dari tempat pendaftaran dimana kami menambahkan prosesor kami.
Dataprosesor
DataProcessor
terdaftar bersama kelas penghubung dan pelaksana dari DataManipulator
yang ditanganinya. Untuk setiap DataManipulator
s yang tidak kekal/kekal minimal satu DataProcessor
harus terdaftar.
dataRegistry.registerDataProcessorAndImpl(HealthData.class, SpongeHealthData.class,
ImmutableHealthData.class, ImmutableSpongeHealthData.class,
new HealthDataProcessor());
Nilaiprosesor
Nilai prosesor terdaftar dibagian bawah dari fungsi yang sama. Untuk setiap Key
beberapa prosesor bisa didaftarkan dengan beberapa panggilan dari metode registeryValueProcessor()
.
dataRegistry.registerValueProcessor(Keys.HEALTH, new HealthValueProcessor());
dataRegistry.registerValueProcessor(Keys.MAX_HEALTH, new MaxHealthValueProcessor());
Melakukan data blok
Blok data berbeda-beda dari satu jenis dengan yang lain dimana hal tersebut di jalankan dengan mencampurkan blok tersebut dengan blok itu sendiri. Ada beberapa metode di org.spongepowered.mixin.core.block.MixinBlock
yang harus diganti untuk menjalankan data untuk setiap blok.
@Mixin(BlockHorizontal.class)
public abstract class MixinBlockHorizontal extends MixinBlock {
[...]
}
supports()
harus kembali benar
jika baik penghubung ImmutableDataManipulator
bisa dialihkan dari Class
yang dilalui sebagai argumen, atau superkelas mendukungnya.
@Override
public boolean supports(Class<? extends ImmutableDataManipulator<?, ?>> immutable) {
return super.supports(immutable) || ImmutableDirectionalData.class.isAssignableFrom(immutable);
}
getStateWithData()
harus kembali baru BlockState
dengan data dari ImmutableDataManipulator
yang dijalankan untuk nya. Jika manipolator tidak didukung secara langsung, metode harus didelegasikan kepada superclass.
@Override
public Optional<BlockState> getStateWithData(IBlockState blockState, ImmutableDataManipulator<?, ?> manipulator) {
if (manipulator instanceof ImmutableDirectionalData) {
final Direction direction = ((ImmutableDirectionalData) manipulator).direction().get();
final EnumFacing facing = DirectionResolver.getFor(direction);
return Optional.of((BlockState) blockState.withProperty(BlockHorizontal.FACING, facing));
}
return super.getStateWithData(blockState, manipulator);
}
getStateWithValue()
sama dengan get StateWithData()
, tetapi bekerja dengan satu Key
s.
@Override
public <E> Optional<BlockState> getStateWithValue(IBlockState blockState, Key<? extends BaseValue<E>> key, E value) {
if (key.equals(Keys.DIRECTION)) {
final Direction direction = (Direction) value;
final EnumFacing facing = DirectionResolver.getFor(direction);
return Optional.of((BlockState) blockState.withProperty(BlockHorizontal.FACING, facing));
}
return super.getStateWithValue(blockState, key, value);
}
Pada akhirnya, getManipulators()
harus mengembalikan dafter semua immutableDataManipulator
s blok yang didukung, bersamaan dengan nial sekarang untuk disajikan IBlockState
. Data tersebut harus mencakup semua ImmutableDataManipulator
s yang berasal dari superclass.
@Override
public List<ImmutableDataManipulator<?, ?>> getManipulators(IBlockState blockState) {
return ImmutableList.<ImmutableDataManipulator<?, ?>>builder()
.addAll(super.getManipulators(blockState))
.add(new ImmutableSpongeDirectionalData(DirectionResolver.getFor(blockState.getValue(BlockHorizontal.FACING))))
.build();
}
Informasi lebih lanjut
Dengan Data
yang merupakan konsep yang sedikit abstrak didalam Sponge, hal tersebut mempersulit untuk memberikan petunjuk umum tentang cara memperoleh data yang dibutuhkan dari kelas-kelas Minecraft itu sendiri. Mungkin akan membantu dengan memperhatikan prosesor yang serupa dengan yang anda kerjakan yang telah dijalankan untuk mendapatkan pemahaman yang lebih baik tentang bagaimana prosesor tersebut mestinya bekerja.
Jika anda terjebak atau tidak yakin tentang aspek-aspek tertentu, silahkan kunjungi #sponeedev
salura IRC, form-forum, atau angkat masalah tersebut di GitHub. Pastikan anda memeriksa ``Data Processor Implementation Checklist<https://github.com/SpongePowered/SpongeCommon/issues/8>`_ untuk persyaratan kontribusi umum.