Универсальные 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
. Проверка будет вызвана только на сервере.
Либо делайте свои пакеты с дополнительной проверкой корректности данных.