Sui Capys , новый прототип Mysten Labs, служит в качестве предварительного просмотра для разработчиков и демонстрирует ключевые возможности экосистемы Sui. В этой децентрализованной игре игроки покупают, обменивают, разводят и украшают капибар, милых южноамериканских полуводных грызунов. Разработчики Sui могут адаптировать многие принципы и примеры кода, изложенные здесь, для своих собственных проектов.
Как программируемые объекты на блокчейне Sui,Кэпис демонстрировать такие принципы, как владение активами, возможность их передачи и поля динамических объектов. Они появляются в кошельке игрока вместе с аксессуарами, включая шляпы, велосипеды и шарфы. Чтобы просмотреть Capys сейчас, перейдите на Капи.арт.
Разработка Sui Capys с помощью Sui Move требовала определения основных модулей, создания типов и, что наиболее важно, создания реестра для записи и проверки Capys. Одной из уникальных особенностей прототипа является возможность скрещивания двух существующих капи, создавая совершенно новый на основе характеристик размножающейся пары.
Повторим еще раз: это предварительная версия для разработчиков, которая демонстрирует уникальные аспекты Sui и предназначена для разработчиков, на которые можно ссылаться при создании собственных проектов. Капи не продаются.
Отказ от ответственности
- Это децентрализованное приложение в настоящее время считается ранней альфа-версией, поэтому оно может быть немного грубоватым.
- Децентрализованное приложение работает на Devnet Суи, который не обладает зрелостью и стабильностью основной сети.
- Eстьизвестная ошибка кошелька Suiв истории транзакций при использовании Capys, и на следующей неделе мы выпустим исправление для кошелька, чтобы решить эту проблему.
- Мы планируем обновить capy.art достандартный адаптер кошелькав ближайшем будущем
- Sui Capys — это демонстрация, созданная специально для того, чтобы вдохновить наше сообщество разработчиков. Это не аирдроп. Пожалуйста, используйте кран ответственно — не спамьте наш сборщик Devnet.
Capy Архитектура
The Приложение Capy (Github)состоит из трех модулей: capy
, capy_items
, и capy_market
. Эти модули определяют Capys, аксессуары и торговый механизм.
Мы начали процесс разработки с определения конкретных принципов, чтобы сделать прототип приятным и эффективным. Следующие принципы помогли определить архитектуру и варианты реализации:
- Capys должны свободно передаваться и использоваться в любом приложении в сети.
- Типы должны содержать минимальный объем данных для поддержания производительности.
- События можно использовать для создания статических данных, которые будут извлечены индексатором.
- Прототип должен быть расширяемым, чтобы позже можно было добавить новые свойства.
Разработчики, желающие создавать игры и приложения на Sui, должны начать с определения таких основных концепций, которые будут направлять процесс разработки.
Capy Core
Модуль capy
определяет основные функции Sui Capys: он определяет Capy
тип, а также предоставляет издателю CapyManagerCap
, открывая функции администратора для носителя. Он определяет CapyRegistry
централизованное прототипное состояние и способы его развития.
Тип:Capy
Capy
, основной тип приложения, представляет собой принадлежащий объект с определенным набором атрибутов: 32 гена и дополнительная служебная информация, необходимая для функций прототипа. Capy
имеет две способности key
и store
. Первый делает его доступным активом, а второй допускает бесплатную передачу и упаковку.
- Собственность
gen
отмечает поколение Капи. Первые Capys имеютgen 0
; новые породы имеют поколение своих родителей плюс один, так чтоgen 1
,gen 2
и т. д. - Свойство
src
позволяет отображать изображение в проводнике. Сами Capys не хранят свое полное изображение, поскольку оно является динамическим и может быть изменено при добавлении новых элементов. - Свойство
genes
хранит последовательность генов, 32-байтовый вектор, который используется для расчета признаков и выбора генов для новорожденного во время размножения. - Это
item_count
служебное свойство, отслеживающее количество объектов, прикрепленных к каждому Capy. - Свойство
attributes
хранит удобочитаемые атрибуты, созданные во время размножения. Например,{ “name": "pattern", "value": "panda" }
.
Этот набор полей является минимальным требованием для функций Sui Capys, включая размножение или добавление/удаление элементов.
/// The Capy itself. Every Capy has its unique set of genes,
/// as well as generation and utility information. Ownable, tradeable.
struct Capy has key, store {
id: UID,
gen: u64,
url: Url,
genes: Genes,
item_count: u8,
attributes: vector<Attribute>,
}
Тип: Capy Registry
CapyRegistry
, общий объект, необходимый для размножения, хранит общее количество когда-либо рожденных Capys и содержит псевдослучайное семя, описанное ниже в разделе науки о генах, используемое для отбора генов во время размножения. Он содержит все определения атрибутов, присвоенные новорожденным на стадии размножения.
В прототип можно добавить новые атрибуты, как описано ниже в разделе функций администратора.
/// Every capybara is registered here. CapyRegistry acts as a source of randomness
/// as well as the storage for the main information about the game state.
struct CapyRegistry has key {
id: UID,
capy_born: u64,
capy_hash: vector<u8>,
genes: vector<GeneDefinition>
}
Тип: CapyManagerCap
Это CapyManagerCap
возможность, отправляемая издателю модуля (отправителю транзакции публикации) при публикации модуля. Он разрешает действия администратора во всех модулях, включая capy_items
и capy_market
.
Инициализатор
Capys — это автономное (не универсальное) приложение, поэтому их основная логика может быть запущена в инициализаторе модуля. Функция init
делает две вещи:
- Создает
CapyManagerCap
и отправляет издателю модуля. - Создает и публикует файл
CapyRegistry
.
Функции администратора
Чтобы приложение стало играбельным и имело какой-то смысл, админ должен выполнить ряд действий:
- Функция
add_gene
регистрирует новоеGeneDefinition
в файлеCapyRegistry
. При разведении все существующие в реестре атрибуты присваиваются новому Capy. Если к прототипу был добавлен новыйGeneDefinition
(Атрибут), Capys, рожденные до этого добавления, не получат его, но получат его дети. Каждое определение гена имеет имя и набор селекторов, которые используются для выбора значения каждого атрибута. - Эта
batch
функция позволяет создавать группы Capys с предопределенными генами. Он используется для инициализации и на более поздних этапах для заполнения рынка дополнительными Capys для новых пользователей.
Разведение
Основной частью логики, создающей непредсказуемость и помогающей эволюции прототипа, является capy::breed
функция. Эту функцию может выполнять любой игрок с двумя Капи. Логика этой функции следующая:
- На основе
CapyRegistry.capy_hash
выбора родительских генов для новогоCapy
. - Получить список текущих атрибутов и установить
GeneDefinitions
.CapyRegistry
- Создайте событие с новыми данными Capy.
- Вернуть новый
Capy
(используйтеbreed_and_keep
для отправки отправителю).
public fun breed(
reg: &mut CapyRegistry, c1: &mut Capy, c2: &mut Capy, ctx: &mut TxContext
): Capy {
let id = object::new(ctx);
// Update capy hash in the registry
vec::append(&mut reg.capy_hash, object::uid_to_bytes(&id));
reg.capy_hash = hash(reg.capy_hash);
// compute genes
let genes = compute_genes(®.capy_hash, &c1.genes, &c2.genes, GENES);
let gen = math::max(c1.gen, c2.gen) + 1;
let attributes = get_attributes(®.genes, &genes);
let sender = tx_context::sender(ctx);
emit(CapyBorn { /* ... */ });
// Send newborn to parents.
Capy {
url: img_url(&id),
id,
gen,
genes,
attributes,
item_count: 0,
}
}
Генная наука
Прежде чем мы перейдем к самой интересной части приложения, мы должны отметить, что это решение не обеспечивает абсолютной непредсказуемости, и поэтому не должно использоваться для приложений с высокими ставками. Но он создает некоторую степень случайности, превращая пользовательский ввод в псевдослучайный модификатор.
Действительно интересной и уникальной особенностью этого прототипа является способность breed
двух существующих Capys генерировать третий. Новый Capy наследует характеристики своих родителей.
Функция породы берет двух родительских капи и вычисляет гены новорожденного. Чтобы это действие было честным и случайным, нам нужен алгоритм выбора и начальное число. CapyRegistry
предоставляет семя (хранится как capy_hash
) и обновляется после каждого размножения. Алгоритм следующий:
- Используйте хеш-функцию (
sha3_256
) три раза с солью, чтобы сгенерировать три вектора по 32 байта (отмеченных как A, B и C), полученных из файлаcapy_hash
. - Используйте первый вектор (A) для выбора родительского гена. Если значение N-го байта больше 126, выберите ген первого родителя. В противном случае выберите ген второго родителя. Как показано на диаграмме выше, первый ген будет P2, второй P1, третий P2 и снова четвертый P1 (до N=32).
- Второй вектор (В) определяет вероятность мутации. Если значение в позиции N больше 250, используйте ту же позицию в третьем векторе (C), чтобы выбрать значение для мутации. В этом примере третий ген будет мутировать и его значение будет равно 42.
/// Computes genes for the newborn based on the 'random' seed r0, and parents' genes.
///
/// The `max` parameter affects how many genes should be changed.
/// For example, if the number of genes is 32 but only 4 Attributes defined in the
/// registry, the `max` should be set to 4. Remainder genes should not mutate.
fun compute_genes(r0: &vector<u8>, g1: &Genes, g2: &Genes, max: u64): Genes {
let i = 0;
let s1 = &g1.sequence;
let s2 = &g2.sequence;
let s3 = vec::empty();
let r1 = derive(r0, 1); // for parent gene selection
let r2 = derive(r0, 2); // chance of random mutation
let r3 = derive(r0, 3); // value selector for random mutation
while (i < max) {
let rng = *vec::borrow(&r1, i);
let gene = if (lor(rng, 127)) {
*vec::borrow(s1, i)
} else {
*vec::borrow(s2, i)
};
// There's a tiny chance that a mutation will happen.
if (lor(*vec::borrow(&r2, i), MUTATION_CHANCE)) {
gene = *vec::borrow(&r3, i);
};
vec::push_back(&mut s3, gene);
i = i + 1;
};
Genes { sequence: s3 }
}
Capy Items
Этот чрезвычайно простой модуль определяет носимые предметы, которые можно добавить к каждому Capy, и то, как мы реализуем внешний интерфейс. Элементы могут быть добавлены только администратором Capy, так как для этого требуется авторизация с помощью файла CapyManagerCap
.
/// Wearable item. Has special display in capy.art application
struct CapyItem has key, store {
id: UID,
url: Url,
type: String,
name: String,
}
Управление элементами
Добавление и удаление аксессуаров в Capys используетполя динамических объектов, более эффективная и удобная замена родительско-дочерним объектам в Sui. Динамические поля допускают произвольные имена и могут добавляться и удаляться на лету.
Следующий код добавляет элемент в Capy:
entry fun add_item<T: key + store>(capy: &mut Capy, item: T) {
emit(ItemAdded<T> {
capy_id: object::id(capy),
item_id: object::id(&item)
});
dof::add(&mut capy.id, object::id(&item), item);
}
Capy Market
Чтобы приобретать и продавать Capy
s и CapyItems
, мы создали Capy Market. Этот модуль использует поля динамических объектов и блокирует получение предметов после оплаты их price
. В этой архитектуре торговой площадки один объект торговой площадки существует для одного типа элемента ( CapyMarket<Capy>
продает Capy
s, а другой объект, CapyMarket<CapyItem>
продает аксессуары Capy), списки прикрепляются к торговой площадке в виде полей динамических объектов, а перечисленные объекты прикрепляются к спискам.
+--> Листинг --> T
CapyMarket<T> +--> Листинг --> T
+--> Листинг --> T
Торговая площадка и функция списка
Каждый экземпляр Marketplace обслуживает только один тип. В этом приложении один экземпляр Marketplace существует для Capy
типа, а другой — для CapyItem
типа.
/// A generic marketplace for anything. T marks the type for Listings.
struct CapyMarket<phantom T: key + store> has key { id: UID }
/// A listing for the marketplace. Contains the price and owner of the Listing.
struct Listing<phantom T: key + store> has key, store {
id: UID,
price: u64,
owner: address
}
Функция List
используетДинамические поля. Он делает перечисленный элемент полем а, Listing
а затем делает Listing
поле CapyMarket
.
/// List a new item on the `CapyMarket`.
public entry fun list<T: key + store>(
market: &mut CapyMarket<T>,
item: T,
price: u64,
ctx: &mut TxContext
) {
let id = object::new(ctx);
let item_id = object::id(&item);
let owner = tx_context::sender(ctx);
emit(ItemListed<T> { /* ... */ });
// First attach Item to the Listing with a boolean `true` value;
// Then attach listing to the marketplace through `item.id`;
dynamic_object_field::add(&mut id, true, item);
dynamic_object_field::add(&mut market.id, item_id, Listing<T> {
id, price, owner
});
}
Capy Inspiration
Мы создали прототип Capy, чтобы продемонстрировать некоторые ключевые функции Sui и вдохновить разработчиков на их собственные проекты. Capys использует объектно-ориентированный характер Sui, позволяя игрокам использовать переносные аксессуары, которые игроки могут продавать и покупать, а также создавать новые Capys на основе родительских атрибутов. Мы разработали прототип с возможностью бесконечного расширения, чтобы он порадовал как пользователей, так и разработчиков.
Мы надеемся, что приведенные здесь примеры и код окажутся полезными для разработчиков Sui. Несколько реализаций, которые должны выделиться, включают Capy Market, Accessories и Breeding. Capy Market служит моделью для любого механизма торговли или хранения. Аксессуары показывают хорошее использование Dynamic Fields. Разведение предлагает уникальные средства автоматического создания новых объектов с бесконечными приложениями.
Удачи и удачного развития!
Узнать больше о Sui
- Сайт Sui
- Портал разработчиков Sui
- Переместить язык программирования
- Sui Технический документ
- Форумы сообщества
- Sui Capys Repo
Стройте вместе с нами!
Мы в восторге от того, как разворачивается будущее, и приглашаем создателей и строителей Присоединяйтесь к нам.