diff --git a/packages/client/.env b/packages/client/.env index 3528db88..a7392e67 100644 --- a/packages/client/.env +++ b/packages/client/.env @@ -1 +1 @@ -VITE_CHAIN_ID=31337 +VITE_CHAIN_ID=4242 diff --git a/packages/client/src/components/Battle/index.tsx b/packages/client/src/components/Battle/index.tsx index 5c6739fc..4befa09b 100644 --- a/packages/client/src/components/Battle/index.tsx +++ b/packages/client/src/components/Battle/index.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import duck from "@/assets/img/DarkDuck.svg"; import info from "@/assets/img/battle/info.png"; import attackButton from "@/assets/img/battle/attack-button.png"; @@ -18,100 +18,192 @@ import button5 from "@/assets/img/battle/Button5.png"; import btnBg from "@/assets/img/battle/btn-bg.svg"; import Appearance from '@/components/Appearance'; import "./styles.scss"; +import { useEntityQuery } from "@latticexyz/react"; +import { Has, getComponentValue } from '@latticexyz/recs'; +import { useMUD } from '@/mud/MUDContext'; +import { decodeEntity } from "@latticexyz/store-sync/recs"; +import { getRandomStr } from '@/utils/utils'; +import { ethers } from 'ethers'; +import { solidityKeccak256 } from 'ethers/lib/utils'; +import { message } from 'antd'; export default function Battle(props) { + console.log(props) + const [nonceHex, setNonceHex] = useState(''); const [selectActionData, setSelectActionData] = useState(''); const [selectTacticData, setSelectTacticData] = useState(''); - const [player2LossData, setPlayer2LossData] = useState(0); - const [player1LossData, setPlayer1LossData] = useState(0); const [confirmBattleData, setConfirmBattleData] = useState([]); const [confirmBattle2Data, setConfirmBattle2Data] = useState([]); + const [battleData, setBattleData] = useState({}); + const [battlesId, setBattlesId] = useState(null); + const [battleState, setBattleState] = useState(0); + const [player2LossData, setPlayer2LossData] = useState(0); + const [player1LossData, setPlayer1LossData] = useState(0); - const [player2ResidualData, setPlayer2ResidualData] = useState(1); - const [player1ResidualData, setPlayer1ResidualData] = useState(1); - - const [roundData, setRoundData] = useState(1); + const { + components: { BattleList }, + systemCalls: { confirmBattle, revealBattle }, + network + } = useMUD(); - const setSelectAction = (img: any) => { - setSelectActionData(img); - } - const setSelectTactic = (img: any) => { - setSelectTacticData(img); + const nonce = getRandomStr(18) + if (!nonceHex) { + setNonceHex(ethers.utils.formatBytes32String(nonce)); } - const confirmBattle = () => { - //battle-1 - let battle1 = document.querySelector('.battle-1'); - let battle2 = document.querySelector('.battle-2'); - setConfirmBattleData([selectActionData, selectTacticData]) - let scale1 = 0 - let scale2 = 0 - if (roundData == 1) { - setConfirmBattle2Data([attackButton, rock]) - scale1 = 0.4 - scale2 = 0.4 + + const battles = useEntityQuery([Has(BattleList)]).map((entity) => { + let id = decodeEntity({ battleId: "uint256" }, entity); + let battle:any = getComponentValue(BattleList, entity) + battle.id = id.battleId.toString() + return battle; + }); + if (battles.length) { + let battle:any = battles.filter((item:any) => (item.attacker.toLocaleLowerCase() == props.curPlayer.addr.toLocaleLowerCase() || item.defender.toLocaleLowerCase() == props.curPlayer.addr.toLocaleLowerCase()) && !item.isEnd)[0] + if (battle) { + if (!battlesId) { + setBattlesId(battle.id) + } } - if (roundData == 2) { - setConfirmBattle2Data([attackButton, scissors]) - scale1 = 0.2 - scale2 = 0.0001 + } + if (battlesId) { + let battle:any = battles.filter((item:any) => item.id.toString() == battlesId)[0] + if (((battle.attackerState == 1 && battle.defenderState == 1) || (battle.attackerState == 2 && battle.defenderState == 1) || (battle.attackerState == 1 && battle.defenderState == 2)) && battleState == 1) { + let action = confirmBattleData[0] + let arg = confirmBattleData[1] + let actionHex = ethers.utils.formatBytes32String(action); + revealBattle(battle.id, actionHex, arg, nonceHex) + setBattleState(2) } - if (roundData == 3) { - setConfirmBattle2Data([attackButton, paper]) - scale1 = 0.0001 - scale2 = 0.6 + if ((battle.attackerState == 0 || battle.attackerState == 2) && (battle.defenderState == 0 || battle.defenderState == 2) && battleState == 2) { + setBattleState(3) } - if (battle1 && battle2) { - battle1.classList.add('attack'); - setTimeout(() => { - battle1.classList.remove('attack'); - battle2.classList.add('back'); - setPlayer2LossData(scale2); - // setPlayer2ResidualData(player2ResidualData - .4); - if (player2ResidualData - scale2 <= 0) { - setPlayer2ResidualData(0); - } else { - setPlayer2ResidualData(player2ResidualData - scale2); - } + } - setTimeout(() => { - battle2.classList.remove('back'); - setPlayer2LossData(0); - // console.log(player2ResidualData) - if (player2ResidualData - scale2 <= 0) { - setConfirmBattleData([]); - setConfirmBattle2Data([]); - setTimeout(() => {props.finishBattle(1);}, 600) - return + useEffect(() => { + if (battlesId) { + let battle:any = battles.filter((item:any) => item.id.toString() == battlesId)[0] + if (battle) { + if (!battleData.curHp || !battleData.targetHp) { + let data = { + attackerHP: battle.attackerHP.toString(), + defenderHP: battle.defenderHP.toString(), + attacker: battle.attacker.toLocaleLowerCase(), + defender: battle.defender.toLocaleLowerCase(), } - setTimeout(() => { - battle2.classList.add('attack'); + console.log(data, props.curPlayer.addr, props.targetPlayer.addr) + setBattleData(data) + } + console.log(battleData, battle) + if (battleState == 3) { + let data = battleData + let battle1 = document.querySelector('.battle-1'); + let battle2 = document.querySelector('.battle-2'); + if (battle1 && battle2) { + battle1.classList.add('attack'); setTimeout(() => { - battle2.classList.remove('attack'); - battle1.classList.add('back'); - setPlayer1LossData(scale1); - if (player1ResidualData - scale1 <= 0) { - setPlayer1ResidualData(0); - setConfirmBattleData([]); - setConfirmBattle2Data([]); - props.finishBattle(2); - setTimeout(() => {props.finishBattle(1);}, 200) - return - } else { - setPlayer1ResidualData(player1ResidualData - scale1); - } + battle1.classList.remove('attack'); + battle2.classList.add('back'); + let defenderHP = battle.defenderHP + setPlayer2LossData(Number(data.defenderHP) - Number(defenderHP)) + data.defenderHP = defenderHP + setBattleData(data) setTimeout(() => { - battle1.classList.remove('back'); - setPlayer1LossData(0); - setConfirmBattleData([]); - setConfirmBattle2Data([]); - setRoundData(roundData + 1); + battle2.classList.remove('back'); + setPlayer2LossData(0); + // console.log(player2ResidualData) + if (defenderHP <= 0 || battle.isEnd) { + setTimeout(() => {props.finishBattle(battle.winner);}, 600) + return + } + setTimeout(() => { + battle2.classList.add('attack'); + setTimeout(() => { + battle2.classList.remove('attack'); + battle1.classList.add('back'); + let attackerHP = battle.attackerHP + setPlayer1LossData(Number(data.attackerHP) - Number(attackerHP)) + data.attackerHP = attackerHP + setBattleData(data) + if (attackerHP <= 0 || battle.isEnd) { + setPlayer1ResidualData(0); + setTimeout(() => {props.finishBattle(battle.winner);}, 600) + return + } + setTimeout(() => { + battle1.classList.remove('back'); + setPlayer1LossData(0); + setBattleState(0) + console.log(battleState) + }, 400); + }, 400); + }, 500) }, 400); }, 400); - }, 1000) - }, 400); - }, 400); + } + } + } } + }, [battleState]) + + const setSelectAction = (img: any, action: String) => { + setSelectActionData(img); + let bt:any = confirmBattleData + bt[0] = action + setConfirmBattleData(bt) + } + const setSelectTactic = (img: any, tactic: number) => { + setSelectTacticData(img); + let bt:any = confirmBattleData + bt[1] = tactic + setConfirmBattleData(bt) + } + + const getProofHash = (action, arg, nonce) => { + return solidityKeccak256( + ["bytes32", "uint256", "bytes32"], + [action, arg, nonce] + ) + } + + const confirmBattleFun = () => { + if (battleState != 0) return + if (!confirmBattleData[0]) { + message.info('Please select action') + return + } + let battle:any = battles.filter((item:any) => (item?.attacker?.toLocaleLowerCase() == props?.curPlayer?.addr.toLocaleLowerCase() || item?.defender?.toLocaleLowerCase() == props?.curPlayer?.addr.toLocaleLowerCase()) && !item.isEnd)[0] + console.log(battle) + let action = confirmBattleData[0] + let arg = confirmBattleData[1] || 0 + let actionHex = ethers.utils.formatBytes32String(action); + let hash = getProofHash(actionHex, arg, nonceHex); + confirmBattle(hash, battle.id); + setBattleState(1) } + // const confirmBattle = () => { + // //battle-1 + // let battle1 = document.querySelector('.battle-1'); + // let battle2 = document.querySelector('.battle-2'); + // setConfirmBattleData([selectActionData, selectTacticData]) + // let scale1 = 0 + // let scale2 = 0 + // if (roundData == 1) { + // setConfirmBattle2Data([attackButton, rock]) + // scale1 = 0.4 + // scale2 = 0.4 + // } + // if (roundData == 2) { + // setConfirmBattle2Data([attackButton, scissors]) + // scale1 = 0.2 + // scale2 = 0.0001 + // } + // if (roundData == 3) { + // setConfirmBattle2Data([attackButton, paper]) + // scale1 = 0.0001 + // scale2 = 0.6 + // } + // + // } return (
@@ -120,14 +212,6 @@ export default function Battle(props) {
- { - confirmBattleData.length && confirmBattleData[0] ? ( -
- - -
- ) : '' - }
{ - player1LossData ?
-{(100 * player1LossData).toFixed(0)}
: null + player1LossData ?
-{player1LossData.toFixed(0)}
: null }
- + { + props?.curPlayer?.addr == battleData.attacker ? : + } {/*
- { + {/* { confirmBattle2Data.length && confirmBattle2Data[0] ? (
) : '' - } + } */}
{ - player2LossData ?
-{(100 * player2LossData).toFixed(0)}
: null + player2LossData ?
-{(player2LossData).toFixed(0)}
: null } - {/*
-{160 * player2LossData}
*/}
- + { + props?.curPlayer?.addr == battleData.defender ? : + }
-
HP : {(100 * player1ResidualData).toFixed(0)}/100
+
HP : {battleData.attackerHP}/{props?.curPlayer?.addr == battleData.attacker ? props?.curPlayer?.maxHp.toString() : props?.targetPlayer?.maxHp.toString()}
ATK : 20
-
HP : {(100 * player2ResidualData).toFixed(0)}/100
+
HP : {battleData.defenderHP}/{props?.curPlayer?.addr == battleData.defender ? props?.curPlayer?.maxHp.toString() : props?.targetPlayer?.maxHp.toString()}
ATK : 20
@@ -199,11 +286,11 @@ export default function Battle(props) {
Action
-
setSelectAction(attackButton)}> +
setSelectAction(attackButton, 'attack')}> {/* */}
-
setSelectAction(runButton)}> +
setSelectAction(runButton, 'escape')}> {/* */}
@@ -227,7 +314,7 @@ export default function Battle(props) { {selectTacticData ? : null}
-
+
confirm
@@ -235,15 +322,15 @@ export default function Battle(props) {
Tactic
-
setSelectTactic(rock)}> +
setSelectTactic(rock, 1)}> {/* */}
-
setSelectTactic(scissors)}> +
setSelectTactic(scissors, 2)}> {/* */}
-
setSelectTactic(paper)}> +
setSelectTactic(paper, 3)}> {/* */}
diff --git a/packages/client/src/components/Map/index.tsx b/packages/client/src/components/Map/index.tsx index a930d1f9..0f7a4c7b 100644 --- a/packages/client/src/components/Map/index.tsx +++ b/packages/client/src/components/Map/index.tsx @@ -6,6 +6,7 @@ import { bfs, simplifyMapData } from '@/utils/map'; import useMerkel from '@/hooks/useMerkel'; import { ITreasureChest } from '@/components/TreasureChest'; import GameContext from '@/context'; +import { main } from '../../utils/createMerkelTree'; interface IProps { width: number; @@ -57,9 +58,21 @@ const Map = (props: IProps) => { const cellClassCache = useRef({}); const onMoveTo = (coordinate) => { - const { x, y} = players.find((player) => player.id === curId); + console.log(players, coordinate, 'onMoveTo', curId) + const { x, y} = players.find((player) => player.addr.toLocaleLowerCase() === curId.toLocaleLowerCase()); const paths = bfs(simpleMapData, { x, y }, coordinate).slice(1); onPlayerMove(paths, formatMovePath(paths)); + // 全是1的地图 + // const player = players.find((e) => e.addr.toLocaleLowerCase() === curId.toLocaleLowerCase()); + // let from = {x: player.x, y: player.y} + // let to = coordinate + // let map_info = []; + // let line = Array.from({ length: 100 }, () => 1); + // for (let i = 0; i < 10; i++) { + // map_info.push(line); + // } + // let {merkelData, paths} = main(from, to); + // onPlayerMove(paths, merkelData); } diff --git a/packages/client/src/components/Rank/index.tsx b/packages/client/src/components/Rank/index.tsx index b8624545..77b56616 100644 --- a/packages/client/src/components/Rank/index.tsx +++ b/packages/client/src/components/Rank/index.tsx @@ -15,7 +15,8 @@ interface IProps { const Rank = (props: IProps) => { const { data, curId } = props; - const curIndex = data.findIndex(item => item.id === curId); + console.log(data) + const curIndex = data.findIndex(item => item.id === 1); const [visible, setVisible] = useState(false); const toggleVisible = () => { diff --git a/packages/client/src/components/UserInfo/index.tsx b/packages/client/src/components/UserInfo/index.tsx index 5c6ea5de..0599c351 100644 --- a/packages/client/src/components/UserInfo/index.tsx +++ b/packages/client/src/components/UserInfo/index.tsx @@ -12,7 +12,7 @@ export interface IUserInfo { const UserInfo = (props: IUserInfo) => { - const { handheld, head, clothes, gem = 0 } = props; + const { handheld, head, clothes, gem = 0, userUrl, lootUrl } = props; const lootHasLoaded = handheld && head && clothes; console.log(handheld, head, clothes, lootHasLoaded); @@ -28,10 +28,14 @@ const UserInfo = (props: IUserInfo) => {
- + { + userUrl ? : null + }
- + { + lootUrl ? : null + }
diff --git a/packages/client/src/components/UserInfo/styles.scss b/packages/client/src/components/UserInfo/styles.scss index e9ae2161..ec89f6e8 100644 --- a/packages/client/src/components/UserInfo/styles.scss +++ b/packages/client/src/components/UserInfo/styles.scss @@ -39,16 +39,6 @@ justify-content: space-between; flex-direction: column; height: 100%; - - &.loaded { - .loot-detail:nth-child(1) { - background: url("../../assets/img/loot1.png") no-repeat center / 100%; - } - - .loot-detail:nth-child(2) { - background: url("../../assets/img/loot2.png") no-repeat center / 100%; - } - } } .loot-detail { diff --git a/packages/client/src/components/UserPackage/index.tsx b/packages/client/src/components/UserPackage/index.tsx index ac725f38..8330b7a9 100644 --- a/packages/client/src/components/UserPackage/index.tsx +++ b/packages/client/src/components/UserPackage/index.tsx @@ -18,9 +18,9 @@ const UserPackage = (props: IProps) => {

{props.title}

{ - arr.map((count) => { + arr.map((count, index) => { return ( -
+
{ count > 0 && (<> diff --git a/packages/client/src/hooks/useModal.tsx b/packages/client/src/hooks/useModal.tsx index c8f61ecf..ac72230a 100644 --- a/packages/client/src/hooks/useModal.tsx +++ b/packages/client/src/hooks/useModal.tsx @@ -23,7 +23,7 @@ function useModal(config = { title: '' }) { diff --git a/packages/client/src/mud/createSystemCalls.ts b/packages/client/src/mud/createSystemCalls.ts index e13fc285..e9d60f52 100644 --- a/packages/client/src/mud/createSystemCalls.ts +++ b/packages/client/src/mud/createSystemCalls.ts @@ -59,11 +59,8 @@ export function createSystemCalls( } const selectUserNft = async (tokenId: any) => { - console.log(tokenId, 'tokenId') const tx = await worldContract.write.selectUserNft([tokenId]); - console.log(new Date().getTime(), tx, 'tx') await waitForTransaction(tx); - console.log(new Date().getTime(), tx, 'tx') } const openBox = async (boxId: any) => { diff --git a/packages/client/src/pages/game/index.tsx b/packages/client/src/pages/game/index.tsx index 2290e443..b1bf82af 100644 --- a/packages/client/src/pages/game/index.tsx +++ b/packages/client/src/pages/game/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from "react"; +import React, { useEffect, useRef, useState, useMemo } from "react"; import { useComponentValue, useEntityQuery } from "@latticexyz/react"; import { Has, getComponentValue } from '@latticexyz/recs'; import { decodeEntity } from "@latticexyz/store-sync/recs"; @@ -7,6 +7,7 @@ import { loadMapData } from "@/utils"; import Map from "@/components/Map"; import UserAvatar from "@/components/UserAvatar"; import { useLocation } from "react-router-dom"; +import { message } from 'antd'; import "./styles.scss"; import Rank from "@/components/Rank"; import { CurIdMockData, PlayersMockData, RankMockData, TreasureChestMockData } from "@/mock/data"; @@ -20,42 +21,39 @@ import UserInfoDialog from '@/components/UserInfoDialog'; import { DELIVERY } from '@/config/map'; import { updatePlayerPosition } from '@/utils/player'; import { triggerVertexUpdate } from '@/utils/map'; +import { bfs, simplifyMapData } from '@/utils/map'; +import useMerkel from '@/hooks/useMerkel'; + +let boxId = '' const Game = () => { const { components: { Player, GameConfig, BattleList, BoxList, GlobalConfig }, - systemCalls: { move, getPosition }, + systemCalls: { move, openBox, revealBox, getCollections, battleInvitation }, network, } = useMUD(); - const mudPlayers = useEntityQuery([Has(Player)]).map((entity) => { - const address = decodeEntity({ addr: "address" }, entity)?.addr?.toLocaleLowerCase() || '' - const player = getComponentValue(Player, entity); - player.isMe = address.toLocaleLowerCase() == account.toLocaleLowerCase(); - player.addr = address - return player; - }); - const [renderMapData, setRenderMapData] = useState([]); const [vertexCoordinate, setVertexCoordinate] = useState({ x: 0, y: 0, }); - const [players, setPlayers] = useState([]); + const simpleMapData = useMemo(() => { + return simplifyMapData(renderMapData); + }, [renderMapData]); + + const formatMovePath = useMerkel(simpleMapData); + const [targetPlayer, setTargetPlayer] = useState(null); + const [battleCurPlayer, setBattleCurPlayer] = useState(null); const [userInfoPlayer, setUserInfoPlayer] = useState(); - const [treasureChest, setTreasureChest] = useState(TreasureChestMockData); - const curId = CurIdMockData; const [startBattleData, setStartBattleData] = useState(false); const [userInfoVisible, setUserInfoVisible] = useState(false); const { account } = network; - - const curPlayer = players.find(player => player.isMe); - - console.log(curPlayer, 'curPlayer', mudPlayers) + const curId = account; const { Modal, open, close, setContent } = useModal(); @@ -70,52 +68,99 @@ const Game = () => { head, } = location.state ?? {}; - useEffect(() => { - loadMapData().then((csv) => { - setRenderMapData(csv); - mapDataRef.current = csv; - }); - - if (curPlayer) { - curPlayer.equip = { + const players = useEntityQuery([Has(Player)]).map((entity) => { + const address = decodeEntity({ addr: "address" }, entity)?.addr?.toLocaleLowerCase() || '' + const player = getComponentValue(Player, entity); + player.addr = address + if (address.toLocaleLowerCase() === account.toLocaleLowerCase()) { + player.equip = { clothes, handheld, head, } - curPlayer.username = username; + player.username = username; } + return player; + }).filter(e => e.state != 1); + console.log(players, 'players') + + const curPlayer = players.find(player => player.addr.toLocaleLowerCase() == account.toLocaleLowerCase()); + const battles = useEntityQuery([Has(BattleList)]).map((entity) => { + let id = decodeEntity({ battleId: "uint256" }, entity); + let battle:any = getComponentValue(BattleList, entity) + battle.id = id.battleId.toString() + return battle; + }); - // setPlayers([...players]); + if (battles.length && !startBattleData) { + let battle:any = battles.filter((item:any) => (item.attacker.toLocaleLowerCase() == account.toLocaleLowerCase() || item.defender.toLocaleLowerCase() == account.toLocaleLowerCase()) && !item.isEnd)[0] + if (battle) { + let targetAddr = battle.attacker.toLocaleLowerCase() == account.toLocaleLowerCase() ? battle.defender : battle.attacker + let target = players.filter((item:any) => item.addr.toLocaleLowerCase() == targetAddr.toLocaleLowerCase())[0] + if (!battleCurPlayer) { + setBattleCurPlayer(curPlayer) + } + if (!targetPlayer) { + setTargetPlayer(target) + } + setStartBattleData(true); + } + } + + const getCollectionsFun = (box: any) => { + setContent( +
+
+ Congrats,you got {box.oreBalance} gems! +
+ +
+
+
+ +
+
+ ); + open(); + } + + const boxs = useEntityQuery([Has(BoxList)]).map((entity) => { + let id = decodeEntity({ boxId: "uint256" }, entity); + let box:any = getComponentValue(BoxList, entity) + box.id = id.boxId.toString() + return box; + }); + + useEffect(() => { + loadMapData().then((csv) => { + setRenderMapData(csv); + mapDataRef.current = csv; + }); }, []); useEffect(() => { - // setPlayers(mudPlayers); - }, [mudPlayers]); + if (boxId) { + const box = boxs.find((item) => item.id === boxId); + getCollectionsFun(box); + } + }, [boxs]); const finishBattle = (e: any) => { console.log(e); setStartBattleData(false); - if (e == 1) { + if (e.toLocaleLowerCase() == account.toLocaleLowerCase()) { console.log('win'); - let treasureChestData = treasureChest - console.log(treasureChestData, treasureChestData[treasureChestData.length - 1]); - let item = { - id: treasureChestData.length ? treasureChestData[treasureChestData.length - 1].id + 1 : 1, - x: targetPlayer.x, - y: targetPlayer.y, - gem: targetPlayer.gem - } - treasureChestData.push(item) - let targetPlayerIndex = players.findIndex((item) => item.x === targetPlayer.x && item.y === targetPlayer.y); - players.splice(targetPlayerIndex, 1); - setTreasureChest([...treasureChestData]); - // setPlayers([...players]); - // getWinTreasureChest(targetPlayer.gem) + message.success('You win the battle'); setTargetPlayer(null); - } else if (e == 2) { + } else { console.log('lose'); + message.error('You lose the battle'); } } @@ -126,7 +171,6 @@ const Game = () => { setVertexCoordinate(triggerVertexUpdate(paths[pathIndex], curPlayer, mapDataRef.current, vertexCoordinate)); updatePlayerPosition(curPlayer, paths[pathIndex]); pathIndex++; - setPlayers([...players]); if (pathIndex === paths.length) { clearInterval(moveInterval.current); const target = paths[pathIndex - 1]; @@ -163,7 +207,6 @@ const Game = () => {
@@ -173,66 +216,44 @@ const Game = () => { }, 1000); } - const setStartBattle = (player) => { + const setStartBattle = async (player) => { + console.log(player) + const paths = bfs(simpleMapData, { x: curPlayer.x, y: curPlayer.y }, {x: player.x, y: player.y}).slice(1); + await battleInvitation(player.addr, formatMovePath(paths)); + console.log(formatMovePath(paths)) setTargetPlayer(player); + setBattleCurPlayer(curPlayer) setStartBattleData(true); } - const openTreasureChest = (id) => { - const targetIndex = treasureChest.findIndex(item => item.id === id); - treasureChest[targetIndex].opening = true; - setTreasureChest([...treasureChest]); - - setTimeout(() => { - curPlayer.gem += treasureChest[targetIndex].gem; - setPlayers([...players]); - setContent( -
-
- Congrats,you got {treasureChest[targetIndex].gem} gems! - -
- -
-
-
- -
-
- ); - open(); - }, 3000); - } - - const getWinTreasureChest = (gem = 1) => { - curPlayer.gem += gem; - const targetPlayerData = players.find((item) => item.x === targetPlayer.x && item.y === targetPlayer.y); - targetPlayerData.gem -= gem; - setPlayers([...players]); - setContent( -
-
- Congrats,you got {gem} gems! - -
- -
-
-
- -
-
- ); - open(); + const openTreasureChest = async (id) => { + console.log(id); + const boxIndex = boxs.findIndex(item => item.id === id); + let box = boxs[boxIndex] + if (box.opened) { + if (box.owner.toLocaleLowerCase() != account.toLocaleLowerCase()) { + message.error('The treasure chest has been opened by others'); + return + } else { + getCollectionsFun(box); + return + } + } + boxs[boxIndex].opening = true; + await openBox(id); + let blockNumber = await network.publicClient.getBlockNumber() + // 每隔1s获取一次getBlockNumber + let interval = setInterval(async () => { + let currentBlockNumber = await network.publicClient.getBlockNumber() + console.log(currentBlockNumber, blockNumber, 'currentBlockNumber') + if (currentBlockNumber - blockNumber >= 2) { + clearInterval(interval) + await revealBox(id) + boxId = id + } + }, 1000) } - - - return ( { mapData: renderMapData, onPlayerMove: movePlayer, showUserInfo, - treasureChest, + treasureChest: boxs, openTreasureChest, - setStartBattle, - getWinTreasureChest + setStartBattle }} >
@@ -261,14 +281,14 @@ const Game = () => { />
- + { - startBattleData ? : null + startBattleData ? : null }
diff --git a/packages/client/src/pages/home/index.tsx b/packages/client/src/pages/home/index.tsx index 5d6b577d..1a91140b 100644 --- a/packages/client/src/pages/home/index.tsx +++ b/packages/client/src/pages/home/index.tsx @@ -15,14 +15,20 @@ import { useMUD } from '@/mud/MUDContext'; import { useEntityQuery } from "@latticexyz/react"; import { Has, getComponentValue } from '@latticexyz/recs'; import { ethers } from 'ethers'; +import { min } from 'rxjs'; -const abi = [{"inputs":[{"internalType":"uint256","name":"_waitBlockCount","type":"uint256"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_notRevealedInfo","type":"string"},{"internalType":"string","name":"_revealedDesc","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"randomId","type":"uint256"},{"indexed":false,"internalType":"address","name":"author","type":"address"}],"name":"NewRandom","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getStructInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUserTokenIdList","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"randomId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"randomList","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"address","name":"author","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"revealNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"userList","outputs":[{"internalType":"uint256","name":"randomId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"HP","type":"uint256"},{"internalType":"uint256","name":"Attack","type":"uint256"},{"internalType":"uint256","name":"AttackRange","type":"uint256"},{"internalType":"uint256","name":"Speed","type":"uint256"},{"internalType":"uint256","name":"Strength","type":"uint256"},{"internalType":"uint256","name":"Space","type":"uint256"},{"internalType":"enum MRandom.RandomState","name":"state","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"waitBlockCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] -let userContract +import lootAbi from '../../../../contracts/out/Loot.sol/MLoot.abi.json' +import userAbi from '../../../../contracts/out/User.sol/MUser.abi.json' + +console.log(lootAbi, 'lootAbi') + +let userContract: any +let lootContract: any const Home = () => { const { components: { GlobalConfig }, - systemCalls, + systemCalls: { selectUserNft, joinBattlefield }, network } = useMUD(); @@ -50,19 +56,30 @@ const Home = () => { const [handheld, setHandheld] = useState(); const [head, setHead] = useState(); const [username, setUsername] = useState(); + const [userUrl, setUserUrl] = useState(); + const [lootUrl, setLootUrl] = useState(); const GlobalConfigData = useEntityQuery([Has(GlobalConfig)]).map((entity) => getComponentValue(GlobalConfig, entity)); console.log(GlobalConfigData, 'GlobalConfigData') - // if (GlobalConfigData.length && GlobalConfigData[0].userContract) { + if (GlobalConfigData.length && GlobalConfigData[0].userContract) { let privateKey = network.privateKey let rpc = network.walletClient?.chain?.rpcUrls?.default?.http[0] || 'http://127.0.0.1:8545' let provider = new ethers.providers.JsonRpcProvider(rpc) let wallet = new ethers.Wallet(privateKey, provider) console.log(wallet) - let userContractAddress = '0x5FbDB2315678afecb367f032d93F642f64180aa3' // GlobalConfigData[0].userContract - userContract = new ethers.Contract(userContractAddress, abi, wallet) - // } + let userContractAddress = GlobalConfigData[0].userContract + userContract = new ethers.Contract(userContractAddress, userAbi, wallet) + } + + if (GlobalConfigData.length && GlobalConfigData[0].lootContract && !lootContract) { + let privateKey = network.privateKey + let rpc = network.walletClient?.chain?.rpcUrls?.default?.http[0] || 'http://127.0.0.1:8545' + let provider = new ethers.providers.JsonRpcProvider(rpc) + let wallet = new ethers.Wallet(privateKey, provider) + let lootContractAddress = GlobalConfigData[0].lootContract + lootContract = new ethers.Contract(lootContractAddress, lootAbi, wallet) + } const createWallet = () => { setContent( @@ -102,44 +119,111 @@ const Home = () => { setStep('mint'); } - const mintAndGo = async () => { - const clothes = Duck.Clothes[~~(Math.random() * Duck.Clothes.length)]; - const handheld = Duck.HandHeld[~~(Math.random() * Duck.HandHeld.length)]; - const head = Duck.Head[~~(Math.random() * Duck.Head.length)]; - - setMinting(true); + const mintLoot = async () => { + return new Promise(async (resolve, reject) => { + try { + let tx = await lootContract.mint() + await tx.wait() + console.log(tx, 'tx') + message.success('Mint Loot Success'); + let tokenIds = await lootContract.getUserTokenIdList() + let tokenId = tokenIds[tokenIds.length - 1].toString() + // 获取当前getBlockNumber + let blockNumber = await network.publicClient.getBlockNumber() + // 每隔1s获取一次getBlockNumber + let interval = setInterval(async () => { + let currentBlockNumber = await network.publicClient.getBlockNumber() + if (currentBlockNumber - blockNumber >= 2) { + clearInterval(interval) + let t = await lootContract.revealNFT(tokenId) + await t.wait() + message.success('reveal Loot Success'); + resolve('success') + } + }, 1000) + } catch (error) { + console.log(error) + reject(error) + } + }) + } - if (userContract) { - console.log(userContract, 'userContract') + const mintUser = async () => { + return new Promise(async (resolve, reject) => { try { let tx = await userContract.mint() await tx.wait() console.log(tx, 'tx') - // let tokenIds = await userContract.getUserTokenIdList() - // console.log(tokenIds, 'tokenIds') - let tokenId = '0' - let t = await userContract.revealNFT(tokenId) - await t.wait() - console.log(t, 't') - delay(100).then(() => { - setClothes(clothes); - setHandheld(handheld); - setHead(head); - }).delay(3000).then(() => { - navigate('/game', { - state: { - username, - clothes, - handheld, - head, - } - }); - }) + message.success('Mint User Success'); + let tokenIds = await userContract.getUserTokenIdList() + let tokenId = tokenIds[tokenIds.length - 1].toString() + // 获取当前getBlockNumber + let blockNumber = await network.publicClient.getBlockNumber() + // 每隔1s获取一次getBlockNumber + let interval = setInterval(async () => { + let currentBlockNumber = await network.publicClient.getBlockNumber() + if (currentBlockNumber - blockNumber >= 2) { + clearInterval(interval) + let t = await userContract.revealNFT(tokenId) + await t.wait() + console.log(t, 't') + message.success('reveal User Success'); + resolve('success') + } + }, 1000) } catch (error) { console.log(error) + reject(error) } - } + }) + } + + const atobUrl = (url) => { + url = url.replace('data:application/json;base64,', '') + url = atob(url) + url = JSON.parse(url) + return url + } + const mintAndGo = async () => { + const clothes = Duck.Clothes[~~(Math.random() * Duck.Clothes.length)]; + const handheld = Duck.HandHeld[~~(Math.random() * Duck.HandHeld.length)]; + const head = Duck.Head[~~(Math.random() * Duck.Head.length)]; + + setMinting(true); + await mintUser(); + await mintLoot() + + let tokenIds = await userContract.getUserTokenIdList() + let tokenId = tokenIds[0].toString() + let lootTokenIds = await lootContract.getUserTokenIdList() + let lootTokenId = lootTokenIds[0].toString() + let url = await userContract.tokenURI(tokenId) + let lootUrl = await lootContract.tokenURI(lootTokenId) + + url = atobUrl(url) + lootUrl = atobUrl(lootUrl) + setUserUrl(url.image) + setLootUrl(lootUrl.image) + + await selectUserNft(tokenId) + await joinBattlefield() + + delay(100).then(() => { + setClothes(clothes); + setHandheld(handheld); + setHead(head); + }).delay(3000).then(() => { + setMinting(false); + navigate('/game', { + state: { + username, + clothes, + handheld, + head, + } + }); + }) } const play = () => { @@ -177,7 +261,7 @@ const Home = () => {

HOME

- + diff --git a/packages/client/src/pages/test/index.jsx b/packages/client/src/pages/test/index.jsx index a8c3a327..d0f0c34f 100644 --- a/packages/client/src/pages/test/index.jsx +++ b/packages/client/src/pages/test/index.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import { useComponentValue, useEntityQuery } from "@latticexyz/react"; import { decodeEntity } from "@latticexyz/store-sync/recs"; import { Has, getComponentValue } from '@latticexyz/recs'; @@ -9,9 +9,16 @@ import { ethers } from 'ethers'; import { solidityKeccak256 } from 'ethers/lib/utils'; import { getRandomStr } from '../../utils/utils'; import './index.scss'; +import { bfs, simplifyMapData } from '@/utils/map'; +import useMerkel from '@/hooks/useMerkel'; +import { loadMapData } from "@/utils"; + +import lootAbi from '../../../../contracts/out/Loot.sol/MLoot.abi.json' +import userAbi from '../../../../contracts/out/User.sol/MUser.abi.json' -const abi = [{"inputs":[{"internalType":"uint256","name":"_waitBlockCount","type":"uint256"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_notRevealedInfo","type":"string"},{"internalType":"string","name":"_revealedDesc","type":"string"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"randomId","type":"uint256"},{"indexed":false,"internalType":"address","name":"author","type":"address"}],"name":"NewRandom","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"getStructInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUserTokenIdList","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"randomId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"randomList","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"address","name":"author","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"revealNFT","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"userList","outputs":[{"internalType":"uint256","name":"randomId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"HP","type":"uint256"},{"internalType":"uint256","name":"Attack","type":"uint256"},{"internalType":"uint256","name":"AttackRange","type":"uint256"},{"internalType":"uint256","name":"Speed","type":"uint256"},{"internalType":"uint256","name":"Strength","type":"uint256"},{"internalType":"uint256","name":"Space","type":"uint256"},{"internalType":"enum MRandom.RandomState","name":"state","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"waitBlockCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}] let userContract +let lootContract +let transfering = false const Test = () => { const [stepData, setStepData] = useState([]); @@ -21,8 +28,10 @@ const Test = () => { const [battlesData, setBattlesData] = useState([]); const [boxData, setBoxData] = useState([]); const [boxId, setBoxId] = useState([]); - const [revealNFTData, setRevealNFTData] = useState([]); + const [revealNFTData, setRevealNFTData] = useState(''); const [nftListData, setNftListData] = useState([]); + const [walletBalance, setWalletBalance] = useState(''); + const [renderMapData, setRenderMapData] = useState([]); const { components: { Player, GameConfig, BattleList, BoxList, GlobalConfig }, @@ -31,20 +40,57 @@ const Test = () => { } = useMUD(); const { account } = network; - console.log(network, 'account') - - // PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 转账 - // let PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' - // let provider = new ethers.providers.JsonRpcProvider('http://127.0.0.1:8545') - // let wallet = new ethers.Wallet(PRIVATE_KEY, provider) - // console.log(wallet, 'wallet') - // // 转账到0x6B5A3EF0cEdDE6f8266eCcb7971a6dbdE9D93D44 - // wallet.sendTransaction({ - // to: '0x74F750d72009B2a70aAe2F934B0F0C1F4015A037', - // value: ethers.utils.parseEther('1') - // }).then(res => { - // console.log(res, 'res') - // }) + + const simpleMapData = useMemo(() => { + return simplifyMapData(renderMapData); + }, [renderMapData]); + + const formatMovePath = useMerkel(simpleMapData); + + useEffect(() => { + loadMapData().then((csv) => { + setRenderMapData(csv); + mapDataRef.current = csv; + }); + }, []); + + + // 转账函数 + const transferFun = async (to) => { + if (transfering) return + transfering = true + let PRIVATE_KEY = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' + let rpc = network.walletClient?.chain?.rpcUrls?.default?.http[0] || 'http://127.0.0.1:8545' + let provider = new ethers.providers.JsonRpcProvider(rpc) + let wallet = new ethers.Wallet(PRIVATE_KEY, provider) + console.log(wallet, 'wallet') + wallet.sendTransaction({ + to, + value: ethers.utils.parseEther('1') + }).then(res => { + console.log(res, 'res') + transfering = false + getBalance() + }).catch(err => { + console.log(err) + }) + } + + const getBalance = () => { + network.publicClient.getBalance({ + address: network.walletClient.account.address + }).then(balance => { + if (balance.toString() == 0) { + transferFun(network.walletClient.account.address) + } else { + let walletBalance = (+ethers.utils.formatEther(balance.toString())).toFixed(2) + console.log(walletBalance) + setWalletBalance(walletBalance); + } + }) + } + + getBalance() const GameData = useEntityQuery([Has(GameConfig)]).map((entity) => getComponentValue(GameConfig, entity)); console.log(GameData, 'GameData') @@ -52,13 +98,24 @@ const Test = () => { const GlobalConfigData = useEntityQuery([Has(GlobalConfig)]).map((entity) => getComponentValue(GlobalConfig, entity)); console.log(GlobalConfigData, 'GlobalConfigData') - if (GlobalConfigData.length && GlobalConfigData[0].userContract) { + if (GlobalConfigData.length && GlobalConfigData[0].userContract && !userContract) { + console.log(userAbi, 'userAbi') let privateKey = network.privateKey let rpc = network.walletClient?.chain?.rpcUrls?.default?.http[0] || 'http://127.0.0.1:8545' let provider = new ethers.providers.JsonRpcProvider(rpc) let wallet = new ethers.Wallet(privateKey, provider) let userContractAddress = GlobalConfigData[0].userContract - userContract = new ethers.Contract(userContractAddress, abi, wallet) + userContract = new ethers.Contract(userContractAddress, userAbi, wallet) + } + + if (GlobalConfigData.length && GlobalConfigData[0].lootContract && !lootContract) { + console.log(lootAbi, 'lootAbi') + let privateKey = network.privateKey + let rpc = network.walletClient?.chain?.rpcUrls?.default?.http[0] || 'http://127.0.0.1:8545' + let provider = new ethers.providers.JsonRpcProvider(rpc) + let wallet = new ethers.Wallet(privateKey, provider) + let lootContractAddress = GlobalConfigData[0].lootContract + lootContract = new ethers.Contract(lootContractAddress, lootAbi, wallet) } const battles = useEntityQuery([Has(BattleList)]).map((entity) => { @@ -67,14 +124,8 @@ const Test = () => { console.log(battle, 'battle', id, entity) battle.id = id.battleId.toString() return battle; - }); + }).filter(e => !e.isEnd) console.log(battles, 'battles') - battles.forEach(async item => { - if (item.attackerState == 2 && item.defenderState == 2) { - let hp = await getBattlePlayerHp(item.id, account) - console.log(hp, 'hp') - } - }) const boxs = useEntityQuery([Has(BoxList)]).map((entity) => { let id = decodeEntity({ boxId: "uint256" }, entity); @@ -112,7 +163,6 @@ const Test = () => { } const mintFun = () => { - console.log(1, userContract) userContract.mint().then(async res => { await res.wait() console.log(res) @@ -191,8 +241,8 @@ const Test = () => { let player = players.find(item => item.isMe); let from = {x: player.x, y: player.y} let to = {x: stepData[0], y: stepData[1]} - let merkelData = main(from, to); - move(merkelData); + const paths = bfs(simpleMapData, from, to).slice(1); + move(formatMovePath(paths)); } const transferPlayer = () => { @@ -208,7 +258,8 @@ const Test = () => { let player = players.find(item => item.isMe); let from = {x: player.x, y: player.y} let to = {x: battleData[0], y: battleData[1]} - let merkelData = main(from, to); + const paths = bfs(simpleMapData, from, to).slice(1); + let merkelData = formatMovePath(paths) battleInvitation(tragePlayer.addr, merkelData); } } @@ -280,11 +331,15 @@ const Test = () => { ) } + // useEffect(() => { + // getBalance() + // }); + return (

测试面板

-
当前用户地址:{account}
+
当前用户地址:{account} | {walletBalance} ETH
{ @@ -302,7 +357,7 @@ const Test = () => {
{ - boxs.map((item, index) => (
+ boxs.map((item, index) => (
宝箱信息
id: {item.id}
opened: {item.opened.toString()}
diff --git a/packages/client/src/pages/test/index.scss b/packages/client/src/pages/test/index.scss index 1179d66a..c5326003 100644 --- a/packages/client/src/pages/test/index.scss +++ b/packages/client/src/pages/test/index.scss @@ -22,6 +22,7 @@ align-items: flex-start; justify-content: space-between; min-height: 67px; + flex-wrap: wrap; } .main { diff --git a/packages/client/src/utils/createMerkelTree.js b/packages/client/src/utils/createMerkelTree.js index ab060f60..55cadc31 100644 --- a/packages/client/src/utils/createMerkelTree.js +++ b/packages/client/src/utils/createMerkelTree.js @@ -70,7 +70,7 @@ export const main = (from, to) => { console.log("总移动步数", steps_arr.length); let steps_list = move(steps_arr); console.log("生成的传入文件", steps_list); - return steps_list + return {merkelData: steps_list, paths: steps} } diff --git a/packages/contracts/package.json b/packages/contracts/package.json index ee80c137..1b8f398f 100644 --- a/packages/contracts/package.json +++ b/packages/contracts/package.json @@ -10,7 +10,7 @@ "build:typechain": "rimraf types && typechain --target=ethers-v5 out/IWorld.sol/IWorld.json", "deploy:local": "pnpm run build && mud deploy", "deploy:testnet": "pnpm run build && mud deploy --profile=lattice-testnet", - "dev": "pnpm mud dev-contracts", + "dev": "pnpm mud dev-contracts --rpc http://127.0.0.1:8545", "dev-old": "pnpm mud dev-contracts --rpc http://127.0.0.1:8545", "lint": "pnpm run prettier && pnpm run solhint", "prettier": "prettier --write 'src/**/*.sol'", diff --git a/packages/contracts/script/GameConfigInit.sol b/packages/contracts/script/GameConfigInit.sol index 2888bfe3..66ca1608 100644 --- a/packages/contracts/script/GameConfigInit.sol +++ b/packages/contracts/script/GameConfigInit.sol @@ -9,8 +9,8 @@ import { GAME_CONFIG_KEY } from "../src/Constants.sol"; library GameConfigInit { function initGameConfig(IWorld _world) internal { console.log(" ========= initGameConfig"); - // bytes32 merkleRoot = 0x5df91eca63323dbb115087ef262075c5bcea99b8eaf95f520efb8d48ff447499; - bytes32 merkleRoot = 0xa969691ad8c2e97e3d516e08f5b10ee4decd5f278a5f03ac4fa3532be181c854; + bytes32 merkleRoot = 0x5df91eca63323dbb115087ef262075c5bcea99b8eaf95f520efb8d48ff447499; + // bytes32 merkleRoot = 0xa969691ad8c2e97e3d516e08f5b10ee4decd5f278a5f03ac4fa3532be181c854; GameConfig.set( _world, GAME_CONFIG_KEY, //key diff --git a/packages/contracts/src/other/Loot.sol b/packages/contracts/src/other/Loot.sol index 848240b7..ab5aaa76 100644 --- a/packages/contracts/src/other/Loot.sol +++ b/packages/contracts/src/other/Loot.sol @@ -252,8 +252,22 @@ contract MLoot is Suit, ERC721,MRandom { loot.Ring ); } - - function getUserTokenIdList() view external returns(uint256[] memory){ + function getStructIndexInfo(uint256 _tokenId) external view returns(uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256){ + Loot memory loot = lootList[_tokenId]; + require(loot.state == RandomState.Confirmed,"User not exists"); + return( + indexOf(weapons,loot.Weapon), + indexOf(chestArmor,loot.Chest), + indexOf(headArmor,loot.Head), + indexOf(waistArmor,loot.Waist), + indexOf(footArmor,loot.Foot), + indexOf(handArmor,loot.Hand), + indexOf(necklaces,loot.Neck), + indexOf(rings,loot.Ring) + ); + } + + function getUserTokenIdList() view external returns(uint256[] memory){ uint256 balance = balanceOf(msg.sender); uint256[] memory tokenIds = new uint256[](balance); uint256 index; @@ -268,4 +282,16 @@ contract MLoot is Suit, ERC721,MRandom { } return tokenIds; } + + function indexOf(string[] memory _list,string memory _name) internal pure returns(uint256){ + uint256 r; + require(_list.length > 0,"list is empty"); + for(uint256 i;i<_list.length;i++){ + if(keccak256(abi.encodePacked(_list[i])) == keccak256(abi.encodePacked(_name))){ + r = i; + break; + } + } + return r; + } } diff --git a/packages/contracts/worlds.json b/packages/contracts/worlds.json new file mode 100644 index 00000000..678ac95d --- /dev/null +++ b/packages/contracts/worlds.json @@ -0,0 +1,17 @@ +{ + "4242": { + "address": "0x41dEc9c4BfB2162811790C9cFc83c486bc51fE73", + "blockNumber": 27950347 + }, + "31337": { + "address": "0x2C0Cb6183720432832b4aAC01553eCfc476c1D27" + }, + "421613": { + "address": "0x2Bc1034975c3df48D6f3026802f372677844b85d", + "blockNumber": 46508363 + }, + "11155111": { + "address": "0xec7F8CF3B3640b1C5E8fD3c208776aad056D4fc3", + "blockNumber": 4450305 + } +} \ No newline at end of file