From 8367b92260ba6d5f7af6bbe4b882cb846485e865 Mon Sep 17 00:00:00 2001 From: jovicheng Date: Mon, 9 Oct 2023 13:09:10 +0800 Subject: [PATCH] [feat] add bag --- packages/client/src/components/Bag/index.tsx | 97 +++++ .../client/src/components/Bag/styles.scss | 163 +++++++ packages/client/src/pages/game/index.tsx | 61 +-- .../contracts/src/codegen/tables/MapData.sol | 402 ++++++++++++++++++ .../src/codegen/world/IMapSystem.sol | 10 + 5 files changed, 708 insertions(+), 25 deletions(-) create mode 100644 packages/client/src/components/Bag/index.tsx create mode 100644 packages/client/src/components/Bag/styles.scss create mode 100644 packages/contracts/src/codegen/tables/MapData.sol create mode 100644 packages/contracts/src/codegen/world/IMapSystem.sol diff --git a/packages/client/src/components/Bag/index.tsx b/packages/client/src/components/Bag/index.tsx new file mode 100644 index 00000000..4136118b --- /dev/null +++ b/packages/client/src/components/Bag/index.tsx @@ -0,0 +1,97 @@ +import { useState } from "react"; +import "./styles.scss"; + +export default function Bag() { + const [open, setOpen] = useState(false); + + const [showItemAction, setShowItemAction] = useState(); + + return ( +
+ + {open && ( +
+
+
+
+
MIS
+
+
Mississippi
+
HP: 150
+
ATK: 50
+
Range: 3
+
Speed: 5
+
Weight: 20
+
Pocket: 30
+
+
+
+

Equipment

+
+
+
+
+
+
+
+ +
+

Element

+
+
+
+
+
+ +
+ + +
+ +
+ +
+
+
+
+ {new Array(20).fill(1).map((item, index) => ( +
setShowItemAction(index)} + > + {showItemAction === index && ( +
+
+
item name
+
weight: 999
+
+
+
item desc
+
+
+ + +
+
+ )} +
+ ))} +
+
+
+ )} +
+ ); +} diff --git a/packages/client/src/components/Bag/styles.scss b/packages/client/src/components/Bag/styles.scss new file mode 100644 index 00000000..19e47172 --- /dev/null +++ b/packages/client/src/components/Bag/styles.scss @@ -0,0 +1,163 @@ +@import "../../theme"; + +.mi-bag-wrapper { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + + .mi-bag-button { + position: fixed; + right: 24px; + bottom: 120px; + font-size: 1.5rem; + padding: 24px; + } + + .mi-bag-backdrop { + overflow: hidden; + left: 0; + top: 0; + position: fixed; + height: 100vh; + width: 100vw; + background: rgba($color: #000000, $alpha: 0.6); + display: flex; + align-items: center; + justify-content: center; + + .mi-bag-modal { + min-width: 500px; + height: 600px; + background-color: #d9d9d9; + display: flex; + padding: 48px; + align-items: center; + + &-character { + min-width: 480px; + + &-info { + display: flex; + + &-avatar { + width: 64px; + height: 64px; + background: #eba66e; + display: flex; + justify-content: center; + align-items: center; + border-radius: 999px; + } + + &-detail { + display: flex; + flex-direction: column; + margin-left: 24px; + row-gap: 6px; + } + } + + .mi-bag-equip { + margin-top: 40px; + display: flex; + flex-direction: column; + + &-list { + margin-top: 12px; + display: flex; + align-items: center; + justify-content: space-between; + + &-item { + border: 1px solid #000; + width: 64px; + height: 64px; + border-radius: 12px; + background: #fff; + } + } + } + + &-action { + margin-top: 48px; + display: flex; + align-items: center; + justify-content: center; + + button { + border-radius: 12px; + border: 1px solid #000; + background: #79fb9d; + margin-left: 24px; + padding: 12px; + font-size: 1rem; + } + } + } + + &-divider { + background: #000; + width: 1px; + height: 80%; + margin: 0 24px; + } + + &-bag-list { + display: grid; + grid-template-columns: repeat(5, 18%); + grid-row-gap: 20px; + grid-column-gap: 20px; + + &-item { + width: 64px; + height: 64px; + background: #fff; + border: 1px solid #000; + border-radius: 12px; + position: relative; + + &-action { + background: rgba($color: #000000, $alpha: 0.9); + display: flex; + flex-direction: column; + position: absolute; + padding: 20px; + bottom: -280%; + left: 50%; + color: #fff; + z-index: 9; + width: fit-content; + min-width: 200px; + + &-element-name { + display: flex; + justify-content: space-between; + bottom: 50px; + } + + &-element-desc { + margin-top: 24px; + } + + &-button { + margin-top: 48px; + display: flex; + align-items: center; + justify-content: center; + column-gap: 20px; + + button { + border-radius: 12px; + border: 1px solid #000; + background: #79fb9d; + padding: 12px; + font-size: 1rem; + } + } + } + } + } + } + } +} diff --git a/packages/client/src/pages/game/index.tsx b/packages/client/src/pages/game/index.tsx index f254872e..626f34dd 100644 --- a/packages/client/src/pages/game/index.tsx +++ b/packages/client/src/pages/game/index.tsx @@ -1,22 +1,27 @@ -import React, { useEffect, useRef, useState } from 'react'; -import { MapConfig } from '@/config'; -import { loadMapData } from '@/utils'; -import Map from '@/components/Map'; -import UserAvatar from '@/components/UserAvatar'; -import { useLocation } from 'react-router-dom'; -import './styles.scss'; -import Rank from '@/components/Rank'; +import React, { useEffect, useRef, useState } from "react"; +import { MapConfig } from "@/config"; +import { loadMapData } from "@/utils"; +import Map from "@/components/Map"; +import UserAvatar from "@/components/UserAvatar"; +import { useLocation } from "react-router-dom"; +import "./styles.scss"; +import Rank from "@/components/Rank"; +import Bag from "@/components/Bag"; const Game = () => { const [renderMapData, setRenderMapData] = useState([]); const [vertexCoordinate, setVertexCoordinate] = useState({ x: 0, - y: 0 + y: 0, }); const mapDataRef = useRef([]); const location = useLocation(); - const { username = '', avatar = 'snake', roomId = '000000' } = location.state ?? {}; + const { + username = "", + avatar = "snake", + roomId = "000000", + } = location.state ?? {}; const onKeyDown = (e) => { const mapData = mapDataRef.current; @@ -31,23 +36,28 @@ const Game = () => { vertexCoordinate.y = Math.max(0, vertexCoordinate.y - 1); break; case 39: - vertexCoordinate.x = Math.min(mapData[0].length - 1 - MapConfig.visualWidth, vertexCoordinate.x + 1); + vertexCoordinate.x = Math.min( + mapData[0].length - 1 - MapConfig.visualWidth, + vertexCoordinate.x + 1 + ); break; case 40: - vertexCoordinate.y = Math.min(mapData.length - 1 - MapConfig.visualHeight, vertexCoordinate.y + 1); + vertexCoordinate.y = Math.min( + mapData.length - 1 - MapConfig.visualHeight, + vertexCoordinate.y + 1 + ); break; } setVertexCoordinate({ - ...vertexCoordinate + ...vertexCoordinate, }); - } + }; useEffect(() => { loadMapData().then((csv) => { setRenderMapData(csv); mapDataRef.current = csv; }); - }, []); return ( @@ -67,24 +77,24 @@ const Game = () => { { data={renderMapData} vertexCoordinate={vertexCoordinate} /> + - ) + ); }; -export default Game; \ No newline at end of file +export default Game; diff --git a/packages/contracts/src/codegen/tables/MapData.sol b/packages/contracts/src/codegen/tables/MapData.sol new file mode 100644 index 00000000..20c017fe --- /dev/null +++ b/packages/contracts/src/codegen/tables/MapData.sol @@ -0,0 +1,402 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +/* Autogenerated file. Do not edit manually. */ + +// Import schema type +import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol"; + +// Import store internals +import { IStore } from "@latticexyz/store/src/IStore.sol"; +import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; +import { StoreCore } from "@latticexyz/store/src/StoreCore.sol"; +import { Bytes } from "@latticexyz/store/src/Bytes.sol"; +import { Memory } from "@latticexyz/store/src/Memory.sol"; +import { SliceLib } from "@latticexyz/store/src/Slice.sol"; +import { EncodeArray } from "@latticexyz/store/src/tightcoder/EncodeArray.sol"; +import { Schema, SchemaLib } from "@latticexyz/store/src/Schema.sol"; +import { PackedCounter, PackedCounterLib } from "@latticexyz/store/src/PackedCounter.sol"; + +bytes32 constant _tableId = bytes32(abi.encodePacked(bytes16(""), bytes16("MapData"))); +bytes32 constant MapDataTableId = _tableId; + +struct MapDataData { + uint256 xLen; + uint256 yLen; + int256[] mapArray; +} + +library MapData { + /** Get the table's key schema */ + function getKeySchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](1); + _schema[0] = SchemaType.BYTES32; + + return SchemaLib.encode(_schema); + } + + /** Get the table's value schema */ + function getValueSchema() internal pure returns (Schema) { + SchemaType[] memory _schema = new SchemaType[](3); + _schema[0] = SchemaType.UINT256; + _schema[1] = SchemaType.UINT256; + _schema[2] = SchemaType.INT256_ARRAY; + + return SchemaLib.encode(_schema); + } + + /** Get the table's key names */ + function getKeyNames() internal pure returns (string[] memory keyNames) { + keyNames = new string[](1); + keyNames[0] = "key"; + } + + /** Get the table's field names */ + function getFieldNames() internal pure returns (string[] memory fieldNames) { + fieldNames = new string[](3); + fieldNames[0] = "xLen"; + fieldNames[1] = "yLen"; + fieldNames[2] = "mapArray"; + } + + /** Register the table's key schema, value schema, key names and value names */ + function register() internal { + StoreSwitch.registerTable(_tableId, getKeySchema(), getValueSchema(), getKeyNames(), getFieldNames()); + } + + /** Register the table's key schema, value schema, key names and value names (using the specified store) */ + function register(IStore _store) internal { + _store.registerTable(_tableId, getKeySchema(), getValueSchema(), getKeyNames(), getFieldNames()); + } + + /** Get xLen */ + function getXLen(bytes32 key) internal view returns (uint256 xLen) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 0, getValueSchema()); + return (uint256(Bytes.slice32(_blob, 0))); + } + + /** Get xLen (using the specified store) */ + function getXLen(IStore _store, bytes32 key) internal view returns (uint256 xLen) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + bytes memory _blob = _store.getField(_tableId, _keyTuple, 0, getValueSchema()); + return (uint256(Bytes.slice32(_blob, 0))); + } + + /** Set xLen */ + function setXLen(bytes32 key, uint256 xLen) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + StoreSwitch.setField(_tableId, _keyTuple, 0, abi.encodePacked((xLen)), getValueSchema()); + } + + /** Set xLen (using the specified store) */ + function setXLen(IStore _store, bytes32 key, uint256 xLen) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + _store.setField(_tableId, _keyTuple, 0, abi.encodePacked((xLen)), getValueSchema()); + } + + /** Get yLen */ + function getYLen(bytes32 key) internal view returns (uint256 yLen) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 1, getValueSchema()); + return (uint256(Bytes.slice32(_blob, 0))); + } + + /** Get yLen (using the specified store) */ + function getYLen(IStore _store, bytes32 key) internal view returns (uint256 yLen) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + bytes memory _blob = _store.getField(_tableId, _keyTuple, 1, getValueSchema()); + return (uint256(Bytes.slice32(_blob, 0))); + } + + /** Set yLen */ + function setYLen(bytes32 key, uint256 yLen) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + StoreSwitch.setField(_tableId, _keyTuple, 1, abi.encodePacked((yLen)), getValueSchema()); + } + + /** Set yLen (using the specified store) */ + function setYLen(IStore _store, bytes32 key, uint256 yLen) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + _store.setField(_tableId, _keyTuple, 1, abi.encodePacked((yLen)), getValueSchema()); + } + + /** Get mapArray */ + function getMapArray(bytes32 key) internal view returns (int256[] memory mapArray) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + bytes memory _blob = StoreSwitch.getField(_tableId, _keyTuple, 2, getValueSchema()); + return (SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_int256()); + } + + /** Get mapArray (using the specified store) */ + function getMapArray(IStore _store, bytes32 key) internal view returns (int256[] memory mapArray) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + bytes memory _blob = _store.getField(_tableId, _keyTuple, 2, getValueSchema()); + return (SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_int256()); + } + + /** Set mapArray */ + function setMapArray(bytes32 key, int256[] memory mapArray) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + StoreSwitch.setField(_tableId, _keyTuple, 2, EncodeArray.encode((mapArray)), getValueSchema()); + } + + /** Set mapArray (using the specified store) */ + function setMapArray(IStore _store, bytes32 key, int256[] memory mapArray) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + _store.setField(_tableId, _keyTuple, 2, EncodeArray.encode((mapArray)), getValueSchema()); + } + + /** Get the length of mapArray */ + function lengthMapArray(bytes32 key) internal view returns (uint256) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + uint256 _byteLength = StoreSwitch.getFieldLength(_tableId, _keyTuple, 2, getValueSchema()); + unchecked { + return _byteLength / 32; + } + } + + /** Get the length of mapArray (using the specified store) */ + function lengthMapArray(IStore _store, bytes32 key) internal view returns (uint256) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + uint256 _byteLength = _store.getFieldLength(_tableId, _keyTuple, 2, getValueSchema()); + unchecked { + return _byteLength / 32; + } + } + + /** + * Get an item of mapArray + * (unchecked, returns invalid data if index overflows) + */ + function getItemMapArray(bytes32 key, uint256 _index) internal view returns (int256) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + unchecked { + bytes memory _blob = StoreSwitch.getFieldSlice( + _tableId, + _keyTuple, + 2, + getValueSchema(), + _index * 32, + (_index + 1) * 32 + ); + return (int256(uint256(Bytes.slice32(_blob, 0)))); + } + } + + /** + * Get an item of mapArray (using the specified store) + * (unchecked, returns invalid data if index overflows) + */ + function getItemMapArray(IStore _store, bytes32 key, uint256 _index) internal view returns (int256) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + unchecked { + bytes memory _blob = _store.getFieldSlice( + _tableId, + _keyTuple, + 2, + getValueSchema(), + _index * 32, + (_index + 1) * 32 + ); + return (int256(uint256(Bytes.slice32(_blob, 0)))); + } + } + + /** Push an element to mapArray */ + function pushMapArray(bytes32 key, int256 _element) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + StoreSwitch.pushToField(_tableId, _keyTuple, 2, abi.encodePacked((_element)), getValueSchema()); + } + + /** Push an element to mapArray (using the specified store) */ + function pushMapArray(IStore _store, bytes32 key, int256 _element) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + _store.pushToField(_tableId, _keyTuple, 2, abi.encodePacked((_element)), getValueSchema()); + } + + /** Pop an element from mapArray */ + function popMapArray(bytes32 key) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + StoreSwitch.popFromField(_tableId, _keyTuple, 2, 32, getValueSchema()); + } + + /** Pop an element from mapArray (using the specified store) */ + function popMapArray(IStore _store, bytes32 key) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + _store.popFromField(_tableId, _keyTuple, 2, 32, getValueSchema()); + } + + /** + * Update an element of mapArray at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ + function updateMapArray(bytes32 key, uint256 _index, int256 _element) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + unchecked { + StoreSwitch.updateInField(_tableId, _keyTuple, 2, _index * 32, abi.encodePacked((_element)), getValueSchema()); + } + } + + /** + * Update an element of mapArray (using the specified store) at `_index` + * (checked only to prevent modifying other tables; can corrupt own data if index overflows) + */ + function updateMapArray(IStore _store, bytes32 key, uint256 _index, int256 _element) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + unchecked { + _store.updateInField(_tableId, _keyTuple, 2, _index * 32, abi.encodePacked((_element)), getValueSchema()); + } + } + + /** Get the full data */ + function get(bytes32 key) internal view returns (MapDataData memory _table) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + bytes memory _blob = StoreSwitch.getRecord(_tableId, _keyTuple, getValueSchema()); + return decode(_blob); + } + + /** Get the full data (using the specified store) */ + function get(IStore _store, bytes32 key) internal view returns (MapDataData memory _table) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + bytes memory _blob = _store.getRecord(_tableId, _keyTuple, getValueSchema()); + return decode(_blob); + } + + /** Set the full data using individual values */ + function set(bytes32 key, uint256 xLen, uint256 yLen, int256[] memory mapArray) internal { + bytes memory _data = encode(xLen, yLen, mapArray); + + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + StoreSwitch.setRecord(_tableId, _keyTuple, _data, getValueSchema()); + } + + /** Set the full data using individual values (using the specified store) */ + function set(IStore _store, bytes32 key, uint256 xLen, uint256 yLen, int256[] memory mapArray) internal { + bytes memory _data = encode(xLen, yLen, mapArray); + + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + _store.setRecord(_tableId, _keyTuple, _data, getValueSchema()); + } + + /** Set the full data using the data struct */ + function set(bytes32 key, MapDataData memory _table) internal { + set(key, _table.xLen, _table.yLen, _table.mapArray); + } + + /** Set the full data using the data struct (using the specified store) */ + function set(IStore _store, bytes32 key, MapDataData memory _table) internal { + set(_store, key, _table.xLen, _table.yLen, _table.mapArray); + } + + /** + * Decode the tightly packed blob using this table's schema. + * Undefined behaviour for invalid blobs. + */ + function decode(bytes memory _blob) internal pure returns (MapDataData memory _table) { + // 64 is the total byte length of static data + PackedCounter _encodedLengths = PackedCounter.wrap(Bytes.slice32(_blob, 64)); + + _table.xLen = (uint256(Bytes.slice32(_blob, 0))); + + _table.yLen = (uint256(Bytes.slice32(_blob, 32))); + + // Store trims the blob if dynamic fields are all empty + if (_blob.length > 64) { + // skip static data length + dynamic lengths word + uint256 _start = 96; + uint256 _end; + unchecked { + _end = 96 + _encodedLengths.atIndex(0); + } + _table.mapArray = (SliceLib.getSubslice(_blob, _start, _end).decodeArray_int256()); + } + } + + /** Tightly pack full data using this table's schema */ + function encode(uint256 xLen, uint256 yLen, int256[] memory mapArray) internal pure returns (bytes memory) { + PackedCounter _encodedLengths; + // Lengths are effectively checked during copy by 2**40 bytes exceeding gas limits + unchecked { + _encodedLengths = PackedCounterLib.pack(mapArray.length * 32); + } + + return abi.encodePacked(xLen, yLen, _encodedLengths.unwrap(), EncodeArray.encode((mapArray))); + } + + /** Encode keys as a bytes32 array using this table's schema */ + function encodeKeyTuple(bytes32 key) internal pure returns (bytes32[] memory) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + return _keyTuple; + } + + /* Delete all data for given keys */ + function deleteRecord(bytes32 key) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + StoreSwitch.deleteRecord(_tableId, _keyTuple, getValueSchema()); + } + + /* Delete all data for given keys (using the specified store) */ + function deleteRecord(IStore _store, bytes32 key) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = key; + + _store.deleteRecord(_tableId, _keyTuple, getValueSchema()); + } +} diff --git a/packages/contracts/src/codegen/world/IMapSystem.sol b/packages/contracts/src/codegen/world/IMapSystem.sol new file mode 100644 index 00000000..6044fb86 --- /dev/null +++ b/packages/contracts/src/codegen/world/IMapSystem.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.0; + +/* Autogenerated file. Do not edit manually. */ + +interface IMapSystem { + function initMap(int[] calldata array, uint xLen, uint yLen) external; + + function getPos(uint x, uint y) external view returns (bool); +}