Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…ippi into dev-map
  • Loading branch information
jovicheng committed Oct 9, 2023
2 parents 8367b92 + 8b13c75 commit 8601217
Show file tree
Hide file tree
Showing 20 changed files with 4,097 additions and 449 deletions.
441 changes: 441 additions & 0 deletions packages/client/abi/Mississippi.json

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@
"@latticexyz/store-sync": "2.0.0-next.4",
"@latticexyz/utils": "2.0.0-next.4",
"@latticexyz/world": "2.0.0-next.4",
"@openzeppelin/contracts": "^4.9.3",
"@types/node": "^18.15.11",
"antd": "^5.9.2",
"buffer": "^6.0.3",
"contracts": "workspace:*",
"ethers": "^5.7.2",
"keccak256": "^1.0.6",
"merkletreejs": "^0.3.10",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.16.0",
Expand All @@ -33,8 +37,10 @@
"viem": "1.6.0"
},
"devDependencies": {
"@nomicfoundation/hardhat-toolbox": "^3.0.0",
"@types/react": "^18.0.11",
"@types/react-dom": "^18.0.11",
"hardhat": "^2.17.4",
"vite": "^4.2.1",
"wait-port": "^1.0.4"
}
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ $avatarsPath: './assets/avatar/';
}

.avatar-box {
background-size: 100%;
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
Expand Down
1 change: 1 addition & 0 deletions packages/client/src/components/AvatarSelector/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const AvatarSelector = (props: IProps) => {
Avatars.map((avatar) => {
return (
<li
key={avatar}
className={`avatar-item avatar-box avatar-${avatar}`}
onClick={() => {
setAvatar(avatar);
Expand Down
48 changes: 38 additions & 10 deletions packages/client/src/components/Map/index.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,52 @@
import React, { useEffect, useMemo, useRef } from 'react';
import React, { useMemo, useRef } from 'react';
import { IPlayer } from '../Player';
import MapCell from '../MapCell';
import MapCell, { ICellClassCache, ICoordinate } from '../MapCell';
import './styles.scss';
import { bfs, simplifyMapData } from '@/utils/map';
import useMerkel from '@/hooks/useMerkel';

interface IProps {
width: number;
height: number;
players: IPlayer[];
data: number[][];
curId: number;
vertexCoordinate: {
x: number,
y: number,
}
};
onPlayerMove: (paths: ICoordinate[], simpleMapData: number[][]) => void;
}

const Map = (props: IProps) => {
const { width, height, vertexCoordinate, data } = props;
const { width, height, vertexCoordinate, data = [], players, curId, onPlayerMove } = props;
const { x: startX, y: startY } = vertexCoordinate;

const staticData = useMemo(() => {
return Array(height).fill(0).map(_ => Array(width).fill(0));
return Array(height).fill(0).map(() => Array(width).fill(0));
}, [width, height]);

const cellClassCache = useRef({});
const simpleMapData = useMemo(() => {
return simplifyMapData(data);
}, [data]);

const formatMovePath = useMerkel(simpleMapData);

const playerData = useMemo(() => {
const obj = {};
players.forEach((player) => {
obj[`${player.x}-${player.y}`] = player;
});
return obj;
}, [players]);

const cellClassCache = useRef<ICellClassCache>({});

const onMoveTo = (coordinate) => {
const { x, y} = players.find((player) => player.id === curId);
const paths = bfs(simpleMapData, { x, y }, coordinate).slice(1);
onPlayerMove(paths, formatMovePath(paths));
}


if (data.length === 0) {
Expand All @@ -34,19 +58,23 @@ const Map = (props: IProps) => {
<div className="mi-map-content">
{
staticData.map((row, rowIndex) => {
const y = startY + rowIndex
return (
<div className="mi-map-row" key={startY + rowIndex}>
<div className="mi-map-row" key={y}>
{
row.map((_, colIndex) => {
const x = startX + colIndex;
return (
<MapCell
key={startX + colIndex}
coordinate={{
x: startX + colIndex,
y: startY + rowIndex
x,
y
}}
mapData={data}
cellClassCache={cellClassCache}
cellClassCache={cellClassCache.current}
player={playerData[`${x}-${y}`]}
onMoveTo={onMoveTo}
/>
)
})
Expand Down
1 change: 0 additions & 1 deletion packages/client/src/components/Map/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
.mi-map-content {
border: 1px solid;
width: $cellSize * 24;
font-size: 0;
}

.mi-map-row {
Expand Down
68 changes: 44 additions & 24 deletions packages/client/src/components/MapCell/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import { CellType } from '../../constants';
import { getCellClass } from '../../utils';
import { getCellClass, isMovable } from '@/utils';
import './styles.scss';
import Player, { IPlayer } from '@/components/Player';

interface ITransform {
index: number;
Expand All @@ -13,42 +14,61 @@ interface ICellClass {
classList: number[];
}

export interface ICellClassCache {
[k: string]: ICellClass
}

export interface ICoordinate {
x: number;
y: number;
}

interface IProps {
coordinate: {
x: number;
y: number;
},
coordinate: ICoordinate,
mapData: number[][];
cellClassCache: {
[k: string]: ICellClass
};
cellClassCache: ICellClassCache;
player?: IPlayer;
onMoveTo: (ICoordinate) => void;
}

const MapCell = (props: IProps) => {
const { coordinate: { x, y}, mapData, cellClassCache } = props;
const { coordinate: { x, y}, mapData, cellClassCache, player, onMoveTo } = props;
if (!cellClassCache[`${y}-${x}`]) {
cellClassCache[`${y}-${x}`] = getCellClass(mapData, { x, y});
}

const { transforms, classList } = cellClassCache[`${y}-${x}`]
const { transforms, classList } = cellClassCache[`${y}-${x}`];

const onContextMenu = (e) => {
e.preventDefault();
const curMapDataType = mapData[y][x];
if (isMovable(curMapDataType) && !player) {
onMoveTo({ x, y});
}

}

return (
<div className="mi-map-cell">
<div className="mi-map-cell" onContextMenu={onContextMenu}>
<div className="cell-map-box">
{
classList.map((item, index) => {
const transformStyle = transforms.find((item) => item.index === index);
const style = transformStyle ? {
transform: transformStyle.transform
} : {};
return (
<div
key={`${x}-${y}-${index}`}
className={`inner-cell mi-wall-${item}`}
style={style}
/>
)
})
}
</div>
{
classList.map((item, index) => {
const transformStyle = transforms.find((item) => item.index === index);
const style = transformStyle ? {
transform: transformStyle.transform
} : {};
return (
<div
key={`${x}-${y}-${index}`}
className={`inner-cell mi-wall-${item}`}
style={style}
/>
)
})
player && <Player {...player}/>
}
</div>
);
Expand Down
14 changes: 8 additions & 6 deletions packages/client/src/components/MapCell/styles.scss
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@

.mi-map-cell {
flex-wrap: wrap;
font-size: 0;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
position: relative;

.cell-map-box {
display: grid;
height: 100%;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
}

@for $i from 1 through 25 {
.mi-wall-#{$i} {
Expand Down
9 changes: 6 additions & 3 deletions packages/client/src/components/Player/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import React from 'react';
import './styles.scss';

export interface IPlayer {
x: number;
y: number;

id: number;
username: string;
}

const Player = (props: IPlayer) => {
return (
<div>

<div className="mi-player">
<div className="player-name">{props.username}</div>
<div className="player-body avatar-box avatar-panda"/>
</div>
);
};
Expand Down
13 changes: 13 additions & 0 deletions packages/client/src/components/Player/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.mi-player {
position: absolute;
top: 0;
left: 0;
height: 100%;
display: flex;
flex-direction: column;

.player-body {
flex: 1;
//background: url("");
}
}
6 changes: 3 additions & 3 deletions packages/client/src/components/Rank/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const Rank = (props: IProps) => {
{
data.map((item, index) => {
return (
<li className="rank-info">
<li className="rank-info" key={item.id}>
<div className="rank-index">{index + 1}</div>
<div className="name">{item.name}</div>
<div className="score">{item.score}</div>
Expand All @@ -43,8 +43,8 @@ const Rank = (props: IProps) => {
<div className="name">ME</div>
<div className="score">{data[curIndex].score}</div>
</div>
<div className="opt">
<div className="toggle-visible" onClick={toggleVisible}/>
<div className="opt" onClick={toggleVisible}>
<div className="toggle-visible"/>
</div>
</div>
);
Expand Down
66 changes: 66 additions & 0 deletions packages/client/src/hooks/useMerkel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { useEffect, useRef } from 'react';
import { MerkleTree } from 'merkletreejs';
import { solidityKeccak256, keccak256 } from 'ethers/lib/utils';
import { Buffer } from 'buffer';


const useMerkel = (mapData) => {

const convertToLeafs = (mapData) => {
const result = [];
for (let y = 0; y < mapData.length; y++) {
for (let x = 0; x < mapData[y].length; x++) {
result.push({ x, y, value: mapData[y][x] });
}
}
return result;
}

const leafs = useRef([]);

const merkel = useRef<MerkleTree | null>(null);

const getProof = (x, y) => {
const leaf = generateLeaf(x, y, 1);
return merkel.current!.getHexProof(leaf);
}

// 通过本函数将地图初始化为默克尔树节点的字符串数组,每个字符串的格式为"x,y-value"
// 其中value为0或1,表示该位置是否可以走,默认0不可走,1以及以后数字可以约定分别代表不同的可行性
const generateLeaf = (x, y, value) => {

return Buffer.from(
solidityKeccak256(
["uint16", "string", "uint16", "string", "uint8"],
[x, ",", y, ",", value]
).slice(2),
"hex"
);
}

const formatMovePath = (paths) => {
const steps = paths.map(({ x, y }) => [x, y]);
const result = [];
for (let i = 0; i < steps.length; i++) {
const proof = getProof(steps[i][0], steps[i][1]);
result.push([steps[i][0], steps[i][1], proof]);
}
return result;
}

useEffect(() => {
if (mapData.length === 0) {
return;
}
leafs.current = convertToLeafs(mapData);
merkel.current = new MerkleTree(
leafs.current.map((info) => generateLeaf(info.x, info.y, info.value)),
keccak256,
{ sortPairs: true }
);
}, [mapData]);

return formatMovePath;
}

export default useMerkel;
Loading

0 comments on commit 8601217

Please sign in to comment.