在Sui
Sui Capys是Mysten实验室的新原型,作为开发者预览版,展示了Sui 生态系统的主要功能。
Sui CapysCapys 是 Mysten Labs 的新原型,是开发者的预览版,展示了Sui 生态系统的主要功能。在这款去中心化游戏中,玩家可以购买、交易、饲养和装饰南美半水生啮齿动物卡比巴拉(Capybaras)。Sui 开发人员可以将这里概述的许多原则和代码示例应用到自己的项目中。
Sui 区块链上的可编程对象、 Capys展示了资产所有权、可转让性和 动态对象字段.它们与帽子、自行车和围巾等配件一起出现在玩家的钱包中。现在就预览 Capys,请访问 Capy.art.
使用Sui 上的Move 开发Sui Capys 需要定义基本模块、创建类型,最重要的是建立一个注册表来记录和验证 Capys。原型的一个独特功能是可以繁殖两个现有的 Capys,并根据繁殖对的特征生成一个全新的 Capys。
再次重申,这是一个开发人员预览版,用于展示Sui 的独特之处,供开发人员在构建自己的项目时参考。Capys 不出售。
免责声明
- 该 dApp 目前被认为是早期 Alpha 版,因此边缘可能有些粗糙。
- 该 dApp 在Sui 的 Devnet 上运行,而 Devnet 不具备主网的成熟性和稳定性。
- 有一个 Sui 钱包 bug的交易历史记录,我们将在下周发布钱包修复程序来解决这个问题。
- 我们计划将 capy.art 更新为 钱包适配器标准更新为钱包适配器标准
- Sui Capys 是专为激励我们的开发者社区而制作的演示。这不是空投。请负责任地使用龙头--请勿向我们的 Devnet 龙头发送垃圾邮件。
卡西建筑事务所
Capy 应用程序(Github) 由三个模块组成: 使人振奋
, 项目
和 市场
.这些模块定义了 Capys、配件和交易机制。
在开发过程中,我们首先确定了具体的原则,以使原型令人愉悦并具有良好的性能。以下原则有助于确定架构和实施选择:
- Capys 应可自由转让,并可在任何链上应用中使用。
- 类型应包含最少的数据量,以保持性能。
- 事件可用于发出静态数据,供索引器获取。
- 原型应具有可扩展性,以便以后添加新的属性。
希望在Sui 上开发游戏和应用程序的开发人员应从定义核心概念开始,这些概念将指导开发过程。
卡皮核心
使人振奋
模块定义了Sui Capys 的核心功能:它定义了一个 卡西
类型,并授予发布者一个 CapyManagerCap
,为承载器开启管理功能。它定义了 CapyRegistry
中央集权的原型国家,以及它的发展方式。
类型卡菲
卡西
作为应用程序的主要类型,它是一个具有一组定义属性的自有对象:32 个基因和原型特征所需的附加实用信息。 卡西
有两种能力、 密钥
和 store
.前者使其成为可拥有的资产,后者允许自由转让和包装。
-
基因
财产标志着卡皮一代的诞生。第一代卡皮有gen 0
新的品种有其父母的一代加一代,因此第 1 代
,第二代
等等。 -
来源
属性可以在资源管理器中显示图像。Capys 本身并不存储完整图像,因为它是动态的,在添加新项目时可以更改。 -
基因
该属性存储基因序列,这是一个 32 字节的向量,用于计算属性和在育种过程中为新生儿选择基因。 -
项目数
是一个实用属性,用于跟踪连接到每个 Capy 的对象数量。 -
属性
属性存储育种过程中生成的人类可读属性。例如{ “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>,
}
类型卡西登记处
CapyRegistry
是育种所需的共享对象,它存储了卡皮斯的出生总数,并包含了一个伪随机种子,在下文的基因科学部分将对其进行描述,用于育种过程中的基因选择。它包含在育种阶段分配给新生儿的所有属性定义。
如下文 "管理功能 "部分所述,可以在原型中添加新属性。
/// 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
是模块发布时发送给模块发布者(发布事务的发送者)的一种能力。它授权所有模块的管理操作,包括 项目
和 市场
.
初始化器
Capys 是独立的(非通用)应用程序,因此其主要逻辑可以在模块初始化程序中启动。模块 init
函数做两件事:
- 创建一个
CapyManagerCap
并将其发送给模块发布者。 - 创建并共享
CapyRegistry
.
行政职能
要使应用程序具有可玩性和意义,管理员必须执行一系列操作:
-
添加基因
函数注册一个新的基因定义
在CapyRegistry
.在繁殖过程中,注册表中的所有现有属性都会分配给新的卡西。如果一个新的基因定义
(属性)被添加到原型中,在此之前出生的 Capys 不会获得该属性,但他们的孩子会。每个基因定义都有一个名称和一组选择器,用于选择每个属性的值。 -
批次
功能允许批量创建带有预定义基因的 Capys。该功能用于初始化,并在后期为新用户在市场中添加更多的 Capys。
育种
产生不可预测性和帮助原型进化的主要逻辑是 :繁殖
功能。任何拥有两个 Capys 的玩家都可以执行此功能。该功能的逻辑如下:
- (在Move.toml文件的
CapyRegistry.capy_hash
为新卡西
. - 获取当前
基因定义
从CapyRegistry
并设置属性。 - 发布包含新 Capy 数据的事件。
- 返回一个新的
卡西
(使用繁殖和饲养
发送给发件人)。
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,
}
}
基因科学
在进入应用中最有趣的部分之前,我们必须注意,这种解决方案并不能提供绝对的不可预测性,因此不应用于高风险的应用中。但通过将用户输入转化为伪随机修改器,它确实能产生一定程度的随机性。
该原型的一个非常有趣和独特的功能是可以 培养
两个现有卡比产生第三个卡比。新的卡比会继承其父母的特征。
育种函数接收两个亲代 Capys,并计算新生儿的基因。为了使这一操作公平、随机,我们需要一个选择算法和一个种子。 CapyRegistry
提供了种子(存储为 哈希
),并在每次繁殖后更新。算法如下
- 使用散列函数 (
sha3_256
)三次,用盐生成三个 32 字节的矢量(标记为 A、B 和 C),这些矢量来自哈希
. - 使用第一个向量(A)选择父代基因。如果第 N 个字节的值大于 126,则选择第一个父本基因。否则,选择第二个父本基因。如上图所示,第一个基因为 P2,第二个基因为 P1,第三个基因为 P2,第四个基因为 P1(最多 N=32)。
- 第二个向量(B)定义了突变的几率。如果 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 上的可穿戴项目,以及我们如何实现前端显示。项目只能由 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);
}
卡皮市场
收购和销售 卡西
和 CapyItems
因此,我们创建了 Capy Market。该模块利用动态对象字段并锁定物品,使其在支付费用后即可获得。 价格
.在这种市场架构中,每种物品类型(如:"......")都有一个市场对象。CapyMarket<Capy>
销售 卡西
的同时,也是一个不同的对象、 CapyMarket<CapyItem>
在市场中,列表是作为动态对象字段附加到市场中的,而列出的对象则附加到列表中。
+--> Listing --> T
CapyMarket<T> +--> Listing --> T
+--> Listing --> T
市场和列表功能
每个 Marketplace 实例只服务于一种类型。在此应用程序中,一个 Marketplace 实例为 卡西
类型和另一个 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
}
列表
函数利用 动态字段.它使列出的项目成为 上市
然后使 上市
一个 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 原型,以展示Sui 的一些关键功能,并激励开发人员开发自己的项目。Capys利用Sui"面向对象 "的特性,让玩家可以交易和购买便携式配件,并根据父母的属性生成新的Capys。我们设计的原型可无限扩展,因此用户和开发人员都会非常喜欢。
我们希望这里的示例和代码能对Sui 开发人员有所帮助。其中比较突出的几个实现包括卡比市场、配件和繁殖。卡比市场是任何交易或存储机制的典范。配件展示了对动态字段.育种提供了一种自动生成新对象的独特方法,具有无限的应用前景。