Comment créer un jeu Play To Earn sur NEAR Protocol

import React from “react”;
import BN from “bn.js”;
import * as nearAPI from “near-api-js”;
import { AlphaPicker, HuePicker, GithubPicker } from “react-color”;
import Switch from “react-switch”;
import { Weapons } from “./Weapons”;
import Timer from “react-compound-timer”;
const PixelPrice = new BN(“10000000000000000000000”);
const IsMainnet = window.location.hostname === "berryclub.io";const TestNearConfig = {networkId: "testnet",nodeUrl: "https://rpc.testnet.near.org",contractName: "berryclub.testnet",walletUrl: "https://wallet.testnet.near.org",};const MainNearConfig = {networkId: "mainnet",nodeUrl: "https://rpc.mainnet.near.org",contractName: "berryclub.ek.near",walletUrl: "https://wallet.near.org",};const NearConfig = IsMainnet ? MainNearConfig : TestNearConfig;
const BatchTimeout = 500;const RefreshBoardTimeout = 1000;const MaxWorkTime = 10 * 60 * 1000;const OneDayMs = 24 * 60 * 60 * 1000;
const BoardHeight = 50;const BoardWidth = 50;const NumLinesPerFetch = 50;const ExpectedLineLength = 4 + 8 * BoardWidth;
const CellWidth = 12;const CellHeight = 12;const MaxNumColors = 31;const BatchOfPixels = 100;
pub fn touch(&mut self) -> (Berry, Balance) {let block_timestamp = env::block_timestamp();let time_diff = block_timestamp - self.claim_timestamp;let farm_bonus = if self.farming_preference == Berry::Avocado {1} else {0};let farmed = Balance::from(self.num_pixels + farm_bonus)* Balance::from(time_diff)* REWARD_PER_PIXEL_PER_NANOSEC;self.claim_timestamp = block_timestamp;self.balances[self.farming_preference as usize] += farmed;(self.farming_preference, farmed)}

Numéros aux couleurs et retour

const intToColor = (c) => `#${c.toString(16).padStart(6, "0")}`;const intToColorWithAlpha = (c, a) =>`#${c.toString(16).padStart(6, "0")}${Math.round(255 * a).toString(16).padStart(2, "0")}`;
const rgbaToInt = (cr, cg, cb, ca, bgColor) => {const bb = bgColor & 255;const bg = (bgColor >> 8) & 255;const br = (bgColor >> 16) & 255;  const r = Math.round(cr * ca + br * (1 - ca));const g = Math.round(cg * ca + bg * (1 - ca));const b = Math.round(cb * ca + bb * (1 - ca));return (r << 16) + (g << 8) + b;};
class App extends React.Component {constructor(props) {super(props);
const colors = ["#000000","#666666","#aaaaaa","#FFFFFF","#F44E3B","#D33115","#9F0500","#FE9200","#E27300","#C45100","#FCDC00","#FCC400","#FB9E00","#DBDF00","#B0BC00","#808900","#A4DD00","#68BC00","#194D33","#68CCCA","#16A5A5","#0C797D","#73D8FF","#009CE0","#0062B1","#AEA1FF","#7B64FF","#653294","#FDA1FF","#FA28FF","#AB149E",].map((c) => c.toLowerCase());// const currentColor = parseInt(colors[Math.floor(Math.random() * colors.length)].substring(1), 16);const currentColor = parseInt(colors[0].substring(1), 16);const defaultAlpha = 0.25;
const timeMs = new Date().getTime();const freeDrawingStartMsEstimated =timeMs -((timeMs - new Date("2021-05-09")) % (7 * OneDayMs)) +OneDayMs * 6;
owners: [],accounts: {},highlightedAccountIndex: -1,selectedOwnerIndex: false,farmingBanana: false,
freeDrawingStart: new Date(freeDrawingStartMsEstimated),freeDrawingEnd: new Date(freeDrawingStartMsEstimated + OneDayMs),watchMode: false,
this._buttonDown = false;this._oldCounts = {};this._numFailedTxs = 0;this._balanceRefreshTimer = null;this.canvasRef = React.createRef();this._context = false;this._lines = false;this._queue = [];this._pendingPixels = [];this._refreshBoardTimer = null;this._sendQueueTimer = null;this._stopRefreshTime = new Date().getTime() + MaxWorkTime;this._accounts = {};
this._initNear().then(() => {this.setState({connected: true,signedIn: !!this._accountId,accountId: this._accountId,ircAccountId: this._accountId.replace(".", "_"),freeDrawingStart: this._freeDrawingStart,freeDrawingEnd: this._freeDrawingEnd,},() => {if (window.location.hash.indexOf("watch") >= 0) {setTimeout(() => this.enableWatchMode(), 500);}});});
const click = async () => {if (this.state.watchMode) {return;}
if (this.state.rendering) {await this.drawImg(this.state.selectedCell);} else if (this.state.pickingColor) {this.pickColor(this.state.selectedCell);} else {this.saveColor();await this.drawPixel(this.state.selectedCell);}
if ("touches" in e) {if (e.touches.length > 1) {return true;} else {const rect = e.target.getBoundingClientRect();x = e.targetTouches[0].clientX - rect.left;y = e.targetTouches[0].clientY - rect.top;}} else {x = e.offsetX;y = e.offsetY;}
const mouseDown = async (e) => {this._buttonDown = true;if (this.state.selectedCell !== null) {await click();}};    canvas.addEventListener("mousedown", mouseDown);canvas.addEventListener("touchstart", mouseDown);    const unselectCell = () => {this.setState({selectedCell: null,},() => this.renderCanvas());};    const mouseUp = async (e) => {this._buttonDown = false;if ("touches" in e) {unselectCell();}};    canvas.addEventListener("mouseup", mouseUp);canvas.addEventListener("touchend", mouseUp);    canvas.addEventListener("mouseleave", unselectCell);    canvas.addEventListener("mouseenter", (e) => {if (this._buttonDown) {if (!("touches" in e) && !(e.buttons & 1)) {this._buttonDown = false;}}});
pickColor(cell) {if (!this.state.signedIn || !this._lines || !this._lines[cell.y]) {return;}const color = this._lines[cell.y][cell.x].color;    this.setState({currentColor: color,alpha: 1,pickerColor: intToColorWithAlpha(color, 1),gammaColors: generateGamma(int2hsv(color)[0]),pickingColor: false,},() => {this.renderCanvas();});}
pub struct PixelLine(pub Vec<Pixel>);impl Default for PixelLine {fn default() -> Self {Self(vec![Pixel::default(); BOARD_WIDTH as usize])}}
pub struct PixelBoard {pub lines: Vector<PixelLine>,pub line_versions: Vec<u32>,}
impl Place {pub fn get_lines(&self, lines: Vec<u32>) -> Vec<Base64VecU8> {lines.into_iter().map(|i| {let line = self.board.get_line(i);line.try_to_vec().unwrap().into()}).collect()}    pub fn get_line_versions(&self) -> Vec<u32> {self.board.line_versions.clone()}}
async refreshAllowance() {alert("You're out of access key allowance. Need sign in again to refresh it");await this.logOut();await this.requestSignIn();}
async _sendQueue() {const pixels = this._queue.slice(0, BatchOfPixels);this._queue = this._queue.slice(BatchOfPixels);this._pendingPixels = pixels;    try {await this._contract.draw({pixels,},new BN("75000000000000"));this._numFailedTxs = 0;} catch (error) {const msg = error.toString();if (msg.indexOf("does not have enough balance") !== -1) {await this.refreshAllowance();return;}console.log("Failed to send a transaction", error);this._numFailedTxs += 1;if (this._numFailedTxs < 3) {this._queue = this._queue.concat(this._pendingPixels);this._pendingPixels = [];} else {this._pendingPixels = [];this._queue = [];}}try {await Promise.all([this.refreshBoard(true), this.refreshAccountStats()]);} catch (e) {// ignore}this._pendingPixels.forEach((p) => {if (this._pending[p.y][p.x] === p.color) {this._pending[p.y][p.x] = -1;}});this._pendingPixels = [];}
pub fn draw(&mut self, pixels: Vec<SetPixelRequest>) {if pixels.is_empty() {return;}let mut account = self.get_mut_account(env::predecessor_account_id());let new_pixels = pixels.len() as u32;if ms_time() < self.get_free_drawing_timestamp() {let cost = account.charge(Berry::Avocado, new_pixels);self.burned_balances[Berry::Avocado as usize] += cost;}let mut old_owners = self.board.set_pixels(account.account_index, &pixels);let replaced_pixels = old_owners.remove(&account.account_index).unwrap_or(0);account.num_pixels += new_pixels - replaced_pixels;self.save_account(account);        for (account_index, num_pixels) in old_owners {let mut account = self.get_internal_account_by_index(account_index).unwrap();self.touch(&mut account);account.num_pixels -= num_pixels;self.save_account(account);}        self.maybe_send_reward();}
impl Place {fn maybe_send_reward(&mut self) {let current_time = env::block_timestamp();let next_reward_timestamp: u64 = self.get_next_reward_timestamp().into();if next_reward_timestamp > current_time {return;}self.last_reward_timestamp = current_time;let reward: Balance = self.get_expected_reward().into();env::log(format!("Distributed reward of {}", reward).as_bytes());Promise::new(format!("{}.{}",FARM_CONTRACT_ID_PREFIX,env::current_account_id())).function_call(b"take_my_near".to_vec(),b"{}".to_vec(),reward,GAS_BASE_COMPUTE,);}}
pub fn get_expected_reward(&self) -> U128 {let account_balance = env::account_balance();let storage_usage = env::storage_usage();let locked_for_storage = Balance::from(storage_usage) * STORAGE_PRICE_PER_BYTE + SAFETY_BAR;if account_balance <= locked_for_storage {return 0.into();}let liquid_balance = account_balance - locked_for_storage;let reward = liquid_balance / PORTION_OF_REWARDS;reward.into()}
const PORTION_OF_REWARDS: Balance = 24 * 60;const SAFETY_BAR: Balance = 50_000000_000000_000000_000000;
const FARM_CONTRACT_ID_PREFIX: &str = "farm";

Source :

Médias :

--

--

Blockchain , Near , Octopus Network

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store