美文网首页EOS开发
Oasis(绿洲)

Oasis(绿洲)

作者: 糖果果老师 | 来源:发表于2018-05-20 10:25 被阅读11次

    在我们开始使用代码之前,我们首先需要一个想法。你看过Steven Spielberg的“Ready Player One”电影吗?如果你确实已经知道了绿洲是什么!精彩,对吧?让我们想象一下,我们是将要建立下一个Oasis的团队的一部分,我们的任务是将区块链技术集成到其中,或者至少表明可以完成。我们要做的是一个小型的dApp,它会有玩家。每个玩家都可以玩游戏,并且可以从中获得硬币。随着硬币,他可以去市场购买物品,这会给体力,能力,生命 ,升级。当然,Oasis合同是我们的主要起点。

    开发前准备

    为了能够开发EOS dApps,您需要使用C / C ++的背景,因为这是用于EOS Smart Contracts的编程语言

    • 会使用C / C ++ -

    一个IDE,您可以在其中编写智能合约。我们使用VS Code和C / C ++扩展,但是你可以选择最适合你的。CLion也是一个非常不错的选择

    当然,你需要一个本地testnet节点,但你知道如何构建一个。

    • 一个工作的本地测试网络节点 -

    配置开发环境

    在编写我们的第一份合同之前,我们需要在开发过程中设置一些我们需要的东西。

    步骤1 - 启动节点

    nodeos -e -p eosio --plugin eosio :: wallet_api_plugin --plugin eosio :: chain_api_plugin --plugin eosio :: account_history_api_plugin --resync 
    

    步骤2 - 创建一个电子钱包

    它将存储我们在签署交易时使用的密钥

    # 1. Create new wallet with the name "oasis"
    cleos wallet create -n oasis
    
    # 2. Generate two pair of keys (use the command twice)
    cleos create key
    
    # 3. Import the generated private keys in the wallet(you need to specify the wallet at the end)
    # {private_key_1} - This will be the OwnerKey
    # {private_key_2} - This will be the ActiveKey
    cleos wallet import {private_key_1} -n oasis 
    cleos wallet import {private_key_2} -n oasis 
    
    # 4. Add the private key of the "eosio" account into your wallet
    # Note: With the latest version of EOSIO the private key is automatically added to your wallet
    cleos wallet import 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3 -n oasis
    

    注意:不要忘记保存您的密钥和钱包密码
    EOS.IO智能合约在帐户上运行。因此,需要账户将交易转移或以其他方式推送至区块链。让我们将我们的帐户命名为“ anorak ”。听起来很熟悉?

    # Create the account using the public keys
    cleos create account eosio anorak {public_OwnerKey} {public_ActiveKey}
    
    # "eosio" is the name of the account who will create the new one
    # "anorak" is the name of the new account
    

    项目'绿洲'

    现在是开始开发我们的dApp的时候了!创建一个名为Oasis的项目文件夹。里面添加两个主要的子文件夹 - contracts 和 tests。是的,我们也要写tests。将会有四个子文件夹:Players, Games, Marketplace , Oasis。

    Player智能合约

    玩家将成为我们的第一个EOS智能合约。每个玩家将拥有用户名,等级,生命值,能量值,金币,背包和天赋。他将能够用金币从商店购买物品,并将其添加到他的背包,生命值,能量值或天赋中。为了获得金币,他需要与绿洲的其他玩家一起玩游戏

    在Players文件夹中创建Players.hpp和Players.cpp文件

    1. Player.hpp是包含由.cpp文件引用的变量,常量和函数的头文件。

    2. Player.cpp文件是包含合同功能的源文件。

    我们来深入看一下EOS合约的基本结构

    Players.hpp
    #include <eosiolib/eosio.hpp>
    #include <eosiolib/print.hpp>
    #include <string>
    
    Players.cpp

    在合约开始时,我们设置了我们要使用的所有包含。在我们的例子中,Players.hpp已经拥有了它们,所以在我们的合同实现中只包含头文件就足够了。大多数情况下,当你使用头文件时你会这样做。

    将所有内容都包装在名称空间中是一种很好的做法,因为它与Oasis一起显示在这里。

    #include "Players.hpp"
    
    namespace Oasis {
        using namespace eosio;
        using std::string;
    
        class Players : public contract {
            using contract::contract;
            
            public:
                Players(account_name self):contract(self) {}
    
                //@abi action
                void add(const account_name account, string& username, uint64_t level) {
                    
                }
    
                //@abi action
                void update(const account_name account) {
    
                }
    
                //@abi action
                void getplayer(const account_name account) {
                    
                }
    
            private:
    
                //@abi table player i64
                struct player {
                    uint64_t account_name;
                    string username;
                    uint64_t level;
                    uint64_t health_points = 1000;
                    uint64_t energy_points = 1000;
    
                    uint64_t primary_key() const { return account_name; }
    
                    EOSLIB_SERIALIZE(player, (account_name)(username)(level)(health_points)(energy_points))
                };
    
                typedef multi_index<N(player), player> playerIndex;
        };
    
        EOSIO_ABI(Players, (add)(update)(getplayer))
    }
    

    该Players 继承contract ,并使用它的构造函数(using contract::contract)。

    在开发EOS dApp时,您应该了解的一件重要事情是,智能合约以操作和共享内存数据库访问的形式相互通信。一个合同可以读取另一个合同数据库的状态,只要它包含在具有异步可达的事务的读取范围内。这可以通过使用两种通信模式之一来实现 - inline 和deferred。您可以将它们视为同步和异步
    
    从EOS.IO文档:
    
    inline - 内联保证与当前交易函数一起执行或展开; 无论成功或失败,都不会收到任何通知。内联与原始交易函数具有相同的范围和权限
    deferred - 延期将在稍后由生产者自行决定; 可以传达通信结果或者可以简单地超时。延期可以延伸到不同的范围,并承担发送它们的合同的权力。
    在我们合同的类体中,有两种类型的访问修饰符 - public和private。在公共部分是构造函数和所有动作。一个动作表示智能合约中的单个操作。在我们的合同中,我们add,update和getplayer。我们稍后会看看他们。与此同时,您应该已经注意到,在每个函数之前,我们都有“ // @ abi action ”。它是eosiocpp脚本的指示标志,它将为我们的智能合约生成.abi文件。
    
    在private中,我们保存我们不希望从Player合约外部访问的所有内容。这里我们正在初始化multi_index。这是什么,为什么我们需要它?
    
    //@abi table player i64
    struct player {
      uint64_t account_name;
      string username;
      uint64_t level;
      uint64_t health_points = 1000;
      uint64_t energy_points = 1000;
    
      uint64_t primary_key() const { return username; }
    
      EOSLIB_SERIALIZE(player, (account_name)(username)(level)(health_points)(energy_points))
    };
    
    typedef multi_index<N(player), player> playerIndex;
    

    Actions 实现

    add 负责创建一个玩家

    /@abi action
    void add(const account_name account, string& username) {
        /**
         * We require that only the owner of an account can use this action
         * or somebody with the account authorization
        */
        require_auth(account);
    
        /**
         * We access the "player" table as creating an object of type "playerIndex"
         * As parameters we pass code & scope - _self from the parent contract
        */
        playerIndex players(_self, _self);
    
        /**
         * We must verify that the account doesn't exist yet
         * If the account is not found the iterator variable should be players.end()
        */
        auto iterator = players.find(account);
        eosio_assert(iterator == players.end(), "Address for account already exists");
    
        /**
         * We add the new player in the table
         * The first argument is the payer of the storage which will store the data
        */
        players.emplace(account, [&](auto& player) {
            player.account_name = account;
            player.username = username;
            player.level = 1;
            player.health_points = 1000;
            player.energy_points = 1000;
        });
    }
    

    update 负责更新玩家level, health and energy points . 实现和add相似,只是在更新玩家状态时第一个参数时迭代器

    //@abi action
    void update(account_name account, uint64_t level, int64_t healthPoints, int64_t energyPoints) {
        require_auth(account);
    
        playerIndex players(_self, _self);
    
        auto iterator = players.find(account);
        eosio_assert(iterator != players.end(), "Address for account not found");
    
        /**
         * We add the new player in the table
         * The first argument is the payer of the storage which will store the data
        */
        players.modify(iterator, account, [&](auto& player) {
            player.level = level;
    
            if ((player.health_points - healthPoints) < 0) {
                player.health_points = 0;
            } else {
                player.health_points -= healthPoints;
            }
    
            if ((player.energy_points - energyPoints) < 0) {
                player.energy_points = 0;
            } else {
                player.energy_points -= energyPoints;
            }
        });
    }
    

    getplayer 是一个查询操作,任何人都可以访问 ,不需要认证

    //@abi action
    void getplayer(const account_name account) {
        playerIndex players(_self, _self);
    
        auto iterator = players.find(account);
        eosio_assert(iterator != players.end(), "Address for account not found");
    
        /**
         * The "get" function returns a constant reference to the object
         * containing the specified secondary key
        */
        auto currentPlayer = players.get(account);
        print("Username: ", currentPlayer.username.c_str(), " Level: ", currentPlayer.level, " Health: ", currentPlayer.health_points, " Energy: ", currentPlayer.energy_points);
    }
    

    Player智能合约部署

    生成wast和abi

    //生成wast
    eosiocpp -o Players.wast Players.cpp
    //生成abi
    eosiocpp -g Players.abi Players.cpp
    

    部署

    # cleos set contract {account} {path_to_contract_folder} {path_to_.wast_file} {path_to_.abi_file}
    cleos set contract anorak ./contracts/Players ./contracts/Players/Players.wast ./contracts/Players/Players.abi
    Reading WAST...
    Assembling WASM...
    Publishing contract...
    executed transaction: b3fd7968d08f3e1cece14fed9632c8c678e89f5832b356a3c4c651aa4d3fe159  5668 bytes  10000 cycles
    #         eosio <= eosio::setcode               "000000004073e9340000cf590061736d0100000001cf011d60037f7e7f0060057f7e7e7e7e0060027f7e0060000060057e7...
    #         eosio <= eosio::setabi                "000000004073e934000406706c6179657200050c6163636f756e745f6e616d650675696e74363408757365726e616d65067...
    

    测试

    创建一个玩家
    # cleos push action {account} {action_name} '{data}' -p {account}@active
    cleos push action anorak add '["anorak","art3mis"]' -p anorak@active
    
    executed transaction: 9b099bd072d090424bff9cff3e0473a2ccde98d3554cbffee2392172e4221055  252 bytes  1000 cycles
    #        anorak <= anorak::add                  {"account":"anorak","username":"art3mis"}
    
    查询玩家
    # cleos push action {account} {action} {data}
    # account - The account providing the contract to execute
    # action - The action to execute on the contract
    # data - The arguments to the contract
    cleos push action anorak getplayer '["anorak"]'
    
    executed transaction: 5ecdf264952837e61671b31e935eec6365af8c6430f00f3eafd274e7ca81910d  156 bytes  1000 cycles
    #        anorak <= anorak::getplayer            {"account":"anorak"}
    >> Username: art3mis Level: 1 Health: 1000 Energy: 1000
    
    更新玩家状态
    cleos push action anorak update '["anorak",4,75,110]' -p anorak@active
    
    executed transaction: 0da802b784e9bc2d56d84582e269eae213f6255ca2bbe83c32b6baf9fafc1f54  268 bytes  1000 cycles
    #        anorak <= anorak::update               {"account":"anorak","level":4,"healthPoints":75,"energyPoints":110}
    
    验证更新
    cleos push action anorak getplayer '["anorak"]' -p anorak@active
    
    executed transaction: a82c8356aaaea39ddb544d0fc5486f567c4bbdbb887b752aaf21ff0dd9ee8772  156 bytes  1000 cycles
    #        anorak <= anorak::getplayer            {"account":"anorak"}
    >> Username: art3mis Level: 4 Health: 925 Energy: 890
    

    总结

    from:https://infinitexlabs.com/eos-development-tutorial-part-1/

    相关文章

      网友评论

        本文标题:Oasis(绿洲)

        本文链接:https://www.haomeiwen.com/subject/gipzdftx.html