Skip to main content

Универсальные Capability

Вы решили добавить игроку шкалу маны или добавить всем мобам новый параметр деньги или какие-либо другие данные? Для этого HollowCore предоставляет систему Capability с автоматическим сохранением и синхронизацией данных.

Создание Capability

Для начала наследуйтесь от класса CapabilityInstance и добавьте какой-либо сериализуемый параметр. (с аннотацией @Serializable или наследуемый от ru.hollowhorizon.hc.client.utils.nbt.INBTSerializable)

Далее добавьте аннотацию @HollowCapabilityV2 с параметрами объекта, к которому Capability будет привязана ко всем объектам наследованным от указанного. Доступные варианты: Entity (Игроки тоже), BlockEntity, Level. Также вы можете создать интерфейс и указать его в качестве цели, тогда все объекты реализующие этот интерфейс будут иметь эту Capability.

Пример
@HollowCapabilityV2(Entity::class)
class MoneyCapability : CapabilityInstance() {
var money: Int by syncable(0) // Синхронизируемый параметр типа Int, все примитивные типы тоже сериализуемы
}

Синхронизируемые списки

Создайте делегат при помощи syncableList<T>(), тогда при изменении содержимого списка он автоматически будет изменён и у клиентов.

Пример
@HollowCapabilityV2(Entity::class)
class DataCapability : CapabilityInstance() {
var dataList by syncableList<String>()
}

Примечание: Конструктор должен быть пустым во избежании ошибок

Синхронизируемые Map'ы

Создайте делегат при помощи syncableMap<K, V>(), где K - ключ, а V - значение, тогда при изменении содержимого Map он автоматически будет изменён и у клиентов.

Пример
@HollowCapabilityV2(Entity::class)
class DataCapability : CapabilityInstance() {
var dataList by syncableMap<Int, String>()
}

Примечание: Параметр K рекомендуется использовать только, как примитивный тип, если это возможно. Кроме того, все объекты рекомендуется делать одного типа, т.е. использовать syncableMap<Number, Tag>() - не стоит, это может привести к багам и вылетам.

Использование Capability

Теперь вы можете получить экземпляр вашей Capability. При изменении данных они будут автоматически обновлены у клиентов, а также сохранены при выходе из игры / остановке сервера.

Пример
fun example(entity: Entity) {
val capability = entity[MoneyCapability::class]

val money: Int = capability.money // Получение значения

capability.money = -100 // Изменение значения
}

Как изменить серверное значение будучи на клиенте?

Во избежании уязвимостей по умолчанию такое сделать нельзя, поскольку тогда бы злоумышленники могли бы со стороны клиента изменить значение условных денег на 99999999 и оно бы обновилось так и на клиенте.

Но вы можете добавить метод для проверки на игрока (Например только для модераторов сервера), для этого переопределите внутри Capability метод canAcceptFromClient(player: Player): Boolean. Проверка будет вызвана только на сервере. Либо делайте свои пакеты с дополнительной проверкой корректности данных.