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