Data Attachment API є нещодавнім експериментальним доповненням до Fabric API. Це дозволяє розробникам легко приєднувати довільні дані до сутностей, блоків-сутностей, рівнів та чанків. Укладені дані можна зберігати та синхронізувати за допомогою кодеків кодеків і потоків кодеків, тому вам слід ознайомитися з ними перед використанням.
Створення вкладення даних
Ви почнете з виклику AttachmentRegistry.create. У наведеному нижче прикладі створюється базове вкладення даних, яке не синхронізується та не зберігається під час перезапусків.
java
public static final AttachmentType<String> EXAMPLE_STRING_ATTACHMENT = AttachmentRegistry.create(
Identifier.fromNamespaceAndPath("example-mod", "example_string_attachment") // The ID of your Attachment
);1
2
3
2
3
AttachmentRegistry містить кілька методів для створення основних укладених даних, зокрема:
AttachmentRegistry.create(): створює вкладення даних. Перезапуск гри очистить вкладення.AttachmentRegistry.createPersistent(): створює вкладення даних, яке зберігатиметься між перезапусками гри.AttachmentRegistry.createDefaulted(): створює вкладення даних з усталеним значенням яке можна зчитати за допомогоюgetAttachedOrCreate. Перезапуск гри очистить вкладення.
Поведінку кожного методу також можна відтворити та додатково налаштувати за допомогою параметра builder для create, застосовуючи шаблон ланцюжка методів.
Синхронізація вкладених даних
Якщо вам потрібно, щоб вкладення даних було постійним і синхронізованим між сервером і клієнтами, ви можете встановити таку поведінку за допомогою методу create, який дозволяє налаштовувати через ланцюжок builder. Наприклад:
java
public static final AttachmentType<BlockPos> EXAMPLE_BLOCK_POS_ATTACHMENT = AttachmentRegistry.create(
Identifier.fromNamespaceAndPath("example-mod", "example_block_pos_attachment"),
builder -> builder
.initializer(() -> new BlockPos(0, 0, 0)) // The default value of the Attachment, if one has not been set.
.syncWith(
BlockPos.STREAM_CODEC, // Dictates how to turn the data into a packet to send to clients.
AttachmentSyncPredicate.all() // Dictates who to send the data to.
)
);1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
Наведений вище приклад синхронізується з кожним гравцем, але це може не відповідати вашому випадку використання. Ось деякі інші усталені предикати, але ви також можете створити власні, посилаючись на клас AttachmentSyncPredicate.
AttachmentSyncPredicate.all(): синхронізує вкладення з усіма клієнтами.AttachmentSyncPredicate.targetOnly(): синхронізує вкладення лише з метою, до якої його прикріплено. Зауважте, що синхронізація можлива, лише якщо метою є гравець.AttachmentSyncPredicate.allButTarget(): синхронізує вкладення з кожним клієнтом, окрім цілі, до якої воно прикріплене. Зауважте, що виняток може застосовуватися, лише якщо ціль — гравець.
Постійні вкладення даних
Також можна налаштувати збереження вкладених даних під час перезапуску гри, викликавши метод persistent у ланцюжку конструктора. Він використовує кодек, щоб гра знала, як серіалізувати дані.
За допомогою методу copyOnDeath вони можуть діяти навіть після смерті або перетворення цілі.
java
public static final AttachmentType<BlockPos> EXAMPLE_PERSISTENT_ATTACHMENT = AttachmentRegistry.create(
Identifier.fromNamespaceAndPath("example-mod", "example_block_pos_attachment"),
builder -> builder
.initializer(() -> new BlockPos(0, 0, 0)) // The default value of the Attachment, if one has not been set.
.persistent(BlockPos.CODEC) // Dictates how this Attachment's data should be saved and loaded.
.copyOnDeath() // Dictates that this Attachment should persist even after the entity dies or converts.
);1
2
3
4
5
6
7
2
3
4
5
6
7
Зчитування з вкладених даних
Методи для зчитування з вкладення даних було введено в класи Entity, BlockEntity, ServerLevel і ChunkAccess. Використовувати його так само просто, як викликати один із методів, які повертають значення вкладених даних.
java
// Checks if the given AttachmentType has attached data, returning a boolean.
entity.hasAttached(EXAMPLE_STRING_ATTACHMENT);
// Gets the data associated with the given AttachmentType, or `null` if it doesn't exist.
entity.getAttached(EXAMPLE_STRING_ATTACHMENT);
// Gets the data associated with the given AttachmentType, throwing a `NullPointerException` if it doesn't exist.
entity.getAttachedOrThrow(EXAMPLE_STRING_ATTACHMENT);
// Gets the data associated with the given AttachmentType, setting the value if it doesn't exist.
entity.getAttachedOrSet(EXAMPLE_STRING_ATTACHMENT, "basic");
entity.getAttachedOrSet(EXAMPLE_BLOCK_POS_ATTACHMENT, new BlockPos(0, 0, 0););
// Gets the data associated with the given AttachmentType, returning the provided value if it doesn't exist.
entity.getAttachedOrElse(EXAMPLE_STRING_ATTACHMENT, "basic");
entity.getAttachedOrElse(EXAMPLE_BLOCK_POS_ATTACHMENT, new BlockPos(0, 0, 0););1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Уписання у вкладення даних
Методи для вписування у вкладення даних було введено в класи Entity, BlockEntity, ServerLevel і ChunkAccess. Виклик одного з наведених нижче методів оновить значення вкладених даних і поверне попереднє значення (або null, якщо його не було).
java
// Sets the data associated with the given AttachmentType, returning the previous value.
entity.setAttached(EXAMPLE_STRING_ATTACHMENT, "new value");
// Modifies the data associated with the given AttachmentType in place, returning the currently attached value. Note that currentValue is null if there is no previously attached data.
entity.modifyAttached(EXAMPLE_STRING_ATTACHMENT, currentValue -> "The length was " + (currentValue == null ? 0 : currentValue.length()));
// Removes the data associated with the given AttachmentType, returning the previous value.
entity.removeAttached(EXAMPLE_STRING_ATTACHMENT);1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
WARNING
Ви завжди повинні використовувати значення незмінних типів для вкладення даних, а також оновлювати їх лише за допомогою методів API. В іншому випадку вкладені дані можуть не зберігатися або синхронізуватися належним чином.
Більші вкладення
Хоча вкладення даних можуть зберігати будь-яку форму даних, для якої можна написати кодек, вони сяють під час синхронізації окремих значень. Це пояснюється тим, що вкладення даних є незмінним: зміна частини його значення (наприклад, одного поля об’єкта) означає його повну заміну, що запускає повну синхронізацію для кожного клієнта, який його відстежує.
Натомість ви можете створити складніші вкладення, розділивши їх на кілька полів і впорядкувавши їх за допомогою допоміжного класу. Наприклад, якщо вам потрібні два поля, пов’язані з витривалістю гравця, ви можете створити щось на зразок цього:
java
public class Stamina {
private static final AttachmentType<Integer> CURRENT_STAMINA = AttachmentRegistry.create(
Identifier.fromNamespaceAndPath("example-mod", "current_stamina"),
builder -> builder.syncWith(ByteBufCodecs.INT, AttachmentSyncPredicate.all())
);
private static final AttachmentType<Integer> MAX_STAMINA = AttachmentRegistry.create(
Identifier.fromNamespaceAndPath("example-mod", "max_stamina"),
builder -> builder.syncWith(ByteBufCodecs.INT, AttachmentSyncPredicate.all())
);
public static StaminaData get(AttachmentTarget target) {
return new StaminaData(target);
}
public record StaminaData(AttachmentTarget target) {
public int getCurrentStamina() {
return target.getAttachedOrElse(CURRENT_STAMINA, 0);
}
public int decrementCurrentStamina() {
return target.modifyAttached(CURRENT_STAMINA, currentStamina -> currentStamina-1);
}
public void setCurrentStamina(int value) {
target.setAttached(CURRENT_STAMINA, value);
}
public int getMaxStamina() {
return target.getAttachedOrElse(MAX_STAMINA, 0);
}
public void setMaxStamina(int value) {
target.setAttached(MAX_STAMINA, value);
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
Потім цей допоміжний клас можна використовувати так:
java
Player player = getPlayer();
Stamina.get(player).getCurrentStamina();1
2
2


