EOS(六) - DAPP實踐之小遊戲
阿新 • • 發佈:2019-01-01
這DAPP主要是實現一個小遊戲的智慧合約的實現,是為了提供學習EOS智慧合約用。
1、編譯智慧合約,生成abi檔案
eosiocpp -o mygame.wast mygame.cpp
eosiocpp -g mygame.abi mygame.cpp
2、部署智慧合約 //建立3個使用者賬號 cleos create account eosio banker EOS6zzuh... EOS6zzuh... cleos create account eosio player1 EOS6zzuh... EOS6zzuh... cleos create account eosio player2 EOS6zzuh... EOS6zzuh... //建立一個新遊戲 cleos push action mygame.co creategame '["banker"]' -p banker //玩家開牌 cleos push action mygame.co opencard '[6,1]' -p player1 cleos push action mygame.co opencard '[6,2]' -p player2 //查詢資料表 cleos get table mygame.co mygame.co game 超級節點部署智慧合約: cleos set contract eosio /hom/.../contracts/eosio.bios -p eosio 建立一個智慧合約檔案 eosiocpp -n mytest
3、前端呼叫智慧合約介面
import React from 'react' import ReactDOM from 'react-dom' import EOSJS from 'eosjs' let contract_name = 'mygame.co' let account_name = 'banker' const EOSJS_CONFIG = { contractName: contract_name, //合約名字 contractSender: account_name, //執行合約的賬號(需要與私鑰對應) clientConfig:{ keyProvider:['5Jc...'], //賬號對應的私鑰 httpEndpoint: 'http://172.0.0.1:8888' //EOS節點程式的http終端 } } class LuckPoint extends React.Component { constructor(props){ super(props) this._initGameData = this._initGameData.bind(this) this.gameprops = { gameIndex: -1, gameDataList: []; loading_test: '正在讀取資料...' } this.state = { gameStatus: false, winner: 0 } } componentDidMount(){ this._initGameData() } _initGameData(){ console.log('_initGameData::......') this._updataGameData() } // cleos get tale luckpoint.co luckpoint.co game _updataGameData(){ console.log('_updataGameData::......') this._showLoading(true, '正在讀取遊戲資料... ...') this.gameprops.gameIndex = -1 this.gameprops.gameDataList = [] //讀取遊戲資料 let eosjs = EOSJS.Localnet(EOSJS_CONFIG.clientConfig) eosjs.contract(contract_name) .then((contract)=>{ console.log('_updataGameData::'+contract_name+'合約載入成功!') eosjs.getTableRows({"scope":contract_name, "code":contract_name, "table":"game","json":true}) .then(result => { console.log('_updataGameData::讀取遊戲列表成功') let rows = result.rows let len = rows.length for(let i=0; i<len; i++){ } }) }).catch((err)=>{ console.log('_updataGameData::讀取遊戲列表失敗') }) } // 呼叫智慧合約 _createGame(){ console.log('_createGame::建立遊戲...') this._showLoading(true, '正在建立遊戲... ...') let _sender = account_name let eosjs = EOSJS.Localnet(EOSJS_CONFIG.clientConfig) eosjs.contract(EOSJS_CONFIG.contractName) .then((contract)=>{ console.log('_createGame::載入合約成功') contract.creategame(_sender, {authorization: [_sender] }) .then((res)=>{ console.log('_createGame::遊戲建立成功') this._updataGameData() }) .catch((err)=>{ console.log('_createGame::遊戲建立失敗') }) }) } //開牌 _playerOpenCard(game_id, play_id){ console.log('_playerOpenCard::遊戲ID'+game_id+', 玩家'+play_id+'開牌...') this._showLoading(true, '玩家'+play_id+ '正在開牌...') let _sender = account_name let eosjs = EOSJS.Localnet(EOSJS_CONFIG.clientConfig) eosjs.contract(EOSJS_CONFIG.contractName) .then((contract)=>{ console.log('_playerOpenCard::載入合約成功') contract.opencard(game_id, play_id, {authorization: [_sender]}) .then((res)=>{ console.log('_playerOpenCard::開牌成功') this._updataGameData() }) .catch((err)=>{ console.log('_playerOpenCard::開牌失敗') }) }) } }
4、智慧合約的實現
//mygame.hpp #include <utility> #include <vector> #include <string> #include <eosiolib/eosio.hpp> #include <eosiolib/asset.hpp> using eosio:asset; class mygame: public eosio::contract { public: mygame(account_name self) :eosio::contract(self), globals(_self, _self), games(_self, _self) {} public: void creategame(const account_name _owner); void opencard(uint64_t _gameid, const uint32_t _player); //測試函式 void sayhi(account_name receiver); void printrand(uint64_t _gameid); private: void _checkgame(uint64_t _gameid); void _finishgame(uint64_t _gameid); uint32_t _getrandnum(uint64_t _gameid); private: //@abi table global i64 全域性引用計數表 struct global{ uint64_t id = 0; uint64_t nextgameid = 0; uint64_t primary_key()const { return id; } EOSLIB_SERIALIZE(global, (id)(nextgameid) ) }; //建立一個多索引容器的遊戲引用計數,用於為新遊戲生成ID typedef eosio::multi_index<N(global), global> global_index; global_index globals; //@abi table game i64 遊戲表 struct game { uint64_t id; //遊戲ID uint32_t winner; //勝出者,0還未決勝負,1玩家1勝出,2玩家2勝出 uint32_t player1; //玩家1點數 uint32_t player2; //玩家2點數 time creattime; //建立時間 accunt_name owner; //建立遊戲的賬號 uint64_t primary_key()const { return id; } //設定資料主鍵 EOSLIB_SERIALIZE(game, (id)(winner)(player1)(player2)(creattime)(owner) ) }; //建立一個多索引容器的遊戲列表 typedef eosio::multi_index<N(game), game> game_index; game_index games; }; /////////////////////////////////////////////////////////// //mygame.cpp #include <mygame.hpp> void mygame::creategame(const account_name _owner){ //建立一個全域性引用計數器 auto global_itl = globals.begin(); if( global_itl == globals.end() ){ global_itl = globals.emplace(_self, [&](auto& gitr){ gitr.nextgameid = 0; }); } //增加引用計數器 globals.modify(global_itl, 0, [&](auto& gitr){ gitr.nextgameid++; }); //建立一個新遊戲物件 auto game_itr = games.emplace(_self, [&](auto& new_game){ new_game.id = global_itl->nextgameid; new_game.winner = 0; new_game.player1 = 0; new_game.player2 = 0; new_game.createtime = now(); new_game.owner = _owner; }); } void mygame::opencard(uint64_t _gameid, const uint32_t _player){ eosio_assert(_player == 1 || _player == 2, "the player must is 1 or 2."); auto game_itr = games.find(_gameid); eosio_assert(game_itr != games.end(), "game not found"); //修改遊戲狀態 games.modify(game_itr, 0, [&](auto& gitr){ if(_player == 1){ gitr.player1 = 1; } else if(_player == 2){ gitr.player2 = 1; } //檢查遊戲是否已經決出勝者 _checkgame(_gameid); }); } void mygame::sayhi(account_name receiver){ eosio::print("hi~ luck point world!"); } void mygame::printrand(uint64_t _gameid){ eosio::print("printrand::%d",_getrandnum(_gameid)); } void mygame::_checkgame(uint64_t _gameid){ auto game_itr = games.find(_gameid); eosio_assert(game_itr != ggames.end(), "game not found"); if(game_itr->player1 != 0 && game_itr->player2 !=0){ games.modify(game_itr, 0, [&](auto& gitr){ gitr.winner = _getrandnum(_gameid); }); } } uint32_t mygame::_getrandnum(uint64_t _gameid){ auto game_itr = games.find(_gameid); eosio_assert(game_itr != games.end(), "game id not found in games"); //隨機數=遊戲建立時間,取餘2,再+1,保證是1、2中的任意一個 return (((uint32_t)(game_itr->createtime))%2) + 1; } EOSIO_ABI( mygame, (creategame)(opencard)(sayhi)(printrand))