From d8191131b4f34cf8bd8945d5c89d1d12530426f3 Mon Sep 17 00:00:00 2001
From: ECWireless
Date: Tue, 27 Aug 2024 08:47:01 -0600
Subject: [PATCH 1/2] Add MonstersContext for monster templates
---
.../src/components/BattleOutcomeModal.tsx | 128 ++++-------------
packages/client/src/contexts/ItemsContext.tsx | 5 +-
packages/client/src/contexts/MapContext.tsx | 90 +++++-------
.../client/src/contexts/MonstersContext.tsx | 130 ++++++++++++++++++
packages/client/src/index.tsx | 9 +-
packages/client/src/utils/helpers.ts | 42 +++++-
packages/client/src/utils/types.ts | 18 ++-
7 files changed, 253 insertions(+), 169 deletions(-)
create mode 100644 packages/client/src/contexts/MonstersContext.tsx
diff --git a/packages/client/src/components/BattleOutcomeModal.tsx b/packages/client/src/components/BattleOutcomeModal.tsx
index f93068f72..11870c8dd 100644
--- a/packages/client/src/components/BattleOutcomeModal.tsx
+++ b/packages/client/src/components/BattleOutcomeModal.tsx
@@ -14,26 +14,20 @@ import {
VStack,
} from '@chakra-ui/react';
import { useComponentValue } from '@latticexyz/react';
-import { getComponentValueStrict } from '@latticexyz/recs';
-import { encodeEntity, singletonEntity } from '@latticexyz/store-sync/recs';
+import { encodeEntity } from '@latticexyz/store-sync/recs';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { Link } from 'react-router-dom';
+import { zeroAddress, zeroHash } from 'viem';
import { useBattle } from '../contexts/BattleContext';
import { useCharacter } from '../contexts/CharacterContext';
+import { useItems } from '../contexts/ItemsContext';
import { useMUD } from '../contexts/MUDContext';
import { useToast } from '../hooks/useToast';
import { BATTLE_OUTCOME_SEEN_KEY } from '../utils/constants';
-import {
- decodeArmorStats,
- decodeWeaponStats,
- fetchMetadataFromUri,
- uriToHttp,
-} from '../utils/helpers';
import {
type Armor,
type CombatOutcomeType,
- ItemType,
type Weapon,
} from '../utils/types';
import { ItemCard } from './ItemCard';
@@ -51,8 +45,9 @@ export const BattleOutcomeModal: React.FC = ({
}): JSX.Element => {
const { renderError } = useToast();
const {
- components: { Items, ItemsBaseURI, ItemsTokenURI, Levels },
+ components: { Levels },
} = useMUD();
+ const { armorTemplates, weaponTemplates } = useItems();
const { character } = useCharacter();
const { onContinueToBattleOutcome, opponent } = useBattle();
@@ -81,107 +76,32 @@ export const BattleOutcomeModal: React.FC = ({
}, [character, nextLevelXpRequirement]);
const fetchLootedItems = useCallback(
- async (_lootedItems: string[]) => {
+ (_lootedItemIds: string[]) => {
try {
- const _items = _lootedItems
- .map(tokenId => {
- const tokenIdEntity = encodeEntity(
- { tokenId: 'uint256' },
- { tokenId: BigInt(tokenId) },
- );
-
- const itemTemplate = getComponentValueStrict(Items, tokenIdEntity);
-
+ const _armor = armorTemplates
+ .filter(a => _lootedItemIds.includes(a.tokenId))
+ .map(armor => {
return {
+ ...armor,
balance: '1',
- itemId: tokenIdEntity,
- itemType: itemTemplate.itemType,
- owner: '',
- stats: itemTemplate.stats,
- tokenId: tokenId.toString(),
- tokenIdEntity,
- };
- })
- .sort((a, b) => {
- return Number(a.tokenId) - Number(b.tokenId);
- });
-
- const _armor = _items.filter(item => item.itemType === ItemType.Armor);
- const _weapons = _items.filter(
- item => item.itemType === ItemType.Weapon,
- );
-
- const fullArmor = await Promise.all(
- _armor.map(async item => {
- const decodedArmorStats = decodeArmorStats(item.stats);
-
- const baseURI = getComponentValueStrict(
- ItemsBaseURI,
- singletonEntity,
- ).uri;
-
- const tokenURI = getComponentValueStrict(
- ItemsTokenURI,
- item.tokenIdEntity,
- ).uri;
-
- const metadata = await fetchMetadataFromUri(
- uriToHttp(`${baseURI}${tokenURI}`)[0],
- );
-
- return {
- ...metadata,
- agiModifier: decodedArmorStats.agiModifier,
- armorModifier: decodedArmorStats.armorModifier,
- classRestrictions: decodedArmorStats.classRestrictions,
- hitPointModifier: decodedArmorStats.hitPointModifier,
- intModifier: decodedArmorStats.intModifier,
- itemId: item.itemId,
- owner: item.owner,
- strModifier: decodedArmorStats.strModifier,
- tokenId: item.tokenId,
+ itemId: zeroHash,
+ owner: zeroAddress,
} as Armor;
- }),
- );
-
- const fullWeapons = await Promise.all(
- _weapons.map(async item => {
- const decodedWeaponStats = decodeWeaponStats(item.stats);
-
- const baseURI = getComponentValueStrict(
- ItemsBaseURI,
- singletonEntity,
- ).uri;
-
- const tokenURI = getComponentValueStrict(
- ItemsTokenURI,
- item.tokenIdEntity,
- ).uri;
-
- const metadata = await fetchMetadataFromUri(
- uriToHttp(`${baseURI}${tokenURI}`)[0],
- );
+ });
+ const _weapons = weaponTemplates
+ .filter(w => _lootedItemIds.includes(w.tokenId))
+ .map(weapon => {
return {
- ...metadata,
- agiModifier: decodedWeaponStats.agiModifier,
- balance: item.balance,
- classRestrictions: decodedWeaponStats.classRestrictions,
- hitPointModifier: decodedWeaponStats.hitPointModifier,
- intModifier: decodedWeaponStats.intModifier,
- itemId: item.itemId,
- maxDamage: decodedWeaponStats.maxDamage,
- minDamage: decodedWeaponStats.minDamage,
- minLevel: decodedWeaponStats.minLevel,
- owner: item.owner,
- strModifier: decodedWeaponStats.strModifier,
- tokenId: item.tokenId,
+ ...weapon,
+ balance: '1',
+ itemId: zeroHash,
+ owner: zeroAddress,
} as Weapon;
- }),
- );
+ });
- setArmor(fullArmor);
- setWeapons(fullWeapons);
+ setArmor(_armor);
+ setWeapons(_weapons);
} catch (e) {
renderError(
(e as Error)?.message ?? 'Failed to fetch looted items.',
@@ -191,7 +111,7 @@ export const BattleOutcomeModal: React.FC = ({
setIsLoadingItems(false);
}
},
- [Items, ItemsBaseURI, ItemsTokenURI, renderError],
+ [armorTemplates, renderError, weaponTemplates],
);
useEffect(() => {
diff --git a/packages/client/src/contexts/ItemsContext.tsx b/packages/client/src/contexts/ItemsContext.tsx
index 67ad9649b..85162a87e 100644
--- a/packages/client/src/contexts/ItemsContext.tsx
+++ b/packages/client/src/contexts/ItemsContext.tsx
@@ -204,7 +204,10 @@ export const ItemsProvider = ({
setWeaponTemplates(_weapons);
}
} catch (e) {
- renderError((e as Error)?.message ?? 'Failed to fetch items.', e);
+ renderError(
+ (e as Error)?.message ?? 'Failed to fetch item templates.',
+ e,
+ );
} finally {
setIsLoading(false);
}
diff --git a/packages/client/src/contexts/MapContext.tsx b/packages/client/src/contexts/MapContext.tsx
index 1083d5aa4..445965fc5 100644
--- a/packages/client/src/contexts/MapContext.tsx
+++ b/packages/client/src/contexts/MapContext.tsx
@@ -26,6 +26,7 @@ import {
} from '../utils/helpers';
import { type Character, type Monster } from '../utils/types';
import { useCharacter } from './CharacterContext';
+import { useMonsters } from './MonstersContext';
import { useMUD } from './MUDContext';
type MapContextType = {
@@ -66,7 +67,6 @@ export const MapProvider = ({ children }: MapProviderProps): JSX.Element => {
CharactersTokenURI,
EncounterEntity,
GoldBalances,
- Mobs,
Position,
Spawned,
Stats,
@@ -76,6 +76,7 @@ export const MapProvider = ({ children }: MapProviderProps): JSX.Element => {
network: { publicClient, worldContract },
systemCalls: { spawn },
} = useMUD();
+ const { monsterTemplates } = useMonsters();
const { character, refreshCharacter } = useCharacter();
const [isSpawning, setIsSpawning] = useState(false);
@@ -224,59 +225,36 @@ export const MapProvider = ({ children }: MapProviderProps): JSX.Element => {
);
const getMonsters = useCallback(
- async (
- entities: Entity[],
- ): Promise<
- (Monster & { isSpawned: boolean; position: { x: number; y: number } })[]
- > => {
+ (entities: Entity[]): Monster[] => {
try {
- const _monsters: (Monster & {
- isSpawned: boolean;
- position: { x: number; y: number };
- })[] = await Promise.all(
- entities.map(async entity => {
- const { mobId } = decodeMonsterId(entity as `0x${string}`);
- const mobData = getComponentValueStrict(
- Mobs,
- encodeEntity({ mobId: 'uint256' }, { mobId: BigInt(mobId) }),
- );
- const monsterStats = getComponentValueStrict(Stats, entity);
- const encounterId = getComponentValue(
- EncounterEntity,
- entity,
- )?.encounterId;
- const inBattle = !!encounterId && encounterId !== zeroHash;
-
- const { mobMetadata: metadataURI } = mobData;
-
- const fetachedMetadata = await fetchMetadataFromUri(
- uriToHttp(metadataURI)[0],
- );
-
- const isSpawned = getComponentValueStrict(Spawned, entity).spawned;
- const _position = getComponentValueStrict(Position, entity);
-
- return {
- agility: monsterStats.agility.toString(),
- baseHp: monsterStats.baseHp.toString(),
- currentHp: monsterStats.currentHp.toString(),
- entityClass: monsterStats.class,
- experience: monsterStats.experience.toString(),
- id: entity,
- inBattle,
- intelligence: monsterStats.intelligence.toString(),
- isSpawned,
- level: monsterStats.level.toString(),
- mobId,
- position: { x: _position.x, y: _position.y },
- strength: monsterStats.strength.toString(),
- ...fetachedMetadata,
- } as Monster & {
- isSpawned: boolean;
- position: { x: number; y: number };
- };
- }),
- );
+ const _monsters: Monster[] = entities.map(entity => {
+ const { mobId } = decodeMonsterId(entity as `0x${string}`);
+ const encounterId = getComponentValue(
+ EncounterEntity,
+ entity,
+ )?.encounterId;
+
+ const currentHp = getComponentValueStrict(
+ Stats,
+ entity,
+ ).currentHp.toString();
+ const inBattle = !!encounterId && encounterId !== zeroHash;
+ const isSpawned = getComponentValueStrict(Spawned, entity).spawned;
+ const _position = getComponentValueStrict(Position, entity);
+
+ const monsterTemplate = monsterTemplates.find(
+ m => m.mobId === mobId.toString(),
+ );
+
+ return {
+ ...monsterTemplate,
+ currentHp,
+ id: entity,
+ inBattle,
+ isSpawned,
+ position: { x: _position.x, y: _position.y },
+ } as Monster;
+ });
return _monsters;
} catch (e) {
@@ -284,17 +262,17 @@ export const MapProvider = ({ children }: MapProviderProps): JSX.Element => {
return [];
}
},
- [EncounterEntity, Mobs, Position, renderError, Spawned, Stats],
+ [EncounterEntity, monsterTemplates, Position, renderError, Spawned, Stats],
);
useEffect(() => {
- (async (): Promise => {
+ (async () => {
if (!(allCharacterEntities && allMonsterEntities && isSynced)) return;
const _allCharacters = await getAllCharacters(allCharacterEntities);
setAllCharacters(_allCharacters as Character[]);
- const _monsters = await getMonsters(allMonsterEntities);
+ const _monsters = getMonsters(allMonsterEntities);
setAllMonsters(_monsters);
})();
}, [
diff --git a/packages/client/src/contexts/MonstersContext.tsx b/packages/client/src/contexts/MonstersContext.tsx
new file mode 100644
index 000000000..50d092e0a
--- /dev/null
+++ b/packages/client/src/contexts/MonstersContext.tsx
@@ -0,0 +1,130 @@
+import {
+ getComponentValueStrict,
+ Has,
+ HasValue,
+ runQuery,
+} from '@latticexyz/recs';
+import { decodeEntity, encodeEntity } from '@latticexyz/store-sync/recs';
+import {
+ createContext,
+ ReactNode,
+ useCallback,
+ useContext,
+ useEffect,
+ useState,
+} from 'react';
+
+import { useToast } from '../hooks/useToast';
+import {
+ decodeMonsterStats,
+ fetchMetadataFromUri,
+ uriToHttp,
+} from '../utils/helpers';
+import { MobType, type MonsterTemplate } from '../utils/types';
+import { useMUD } from './MUDContext';
+
+type MonstersContextType = {
+ monsterTemplates: MonsterTemplate[];
+ isLoading: boolean;
+};
+
+const MonstersContext = createContext({
+ monsterTemplates: [],
+ isLoading: false,
+});
+
+export const MonstersProvider = ({
+ children,
+}: {
+ children: ReactNode;
+}): JSX.Element => {
+ const { renderError } = useToast();
+ const {
+ components: { Mobs },
+ isSynced,
+ } = useMUD();
+
+ const [monsterTemplates, setMonsterTemplates] = useState(
+ [],
+ );
+ const [isLoading, setIsLoading] = useState(true);
+
+ const fetchMonsterTemplates = useCallback(
+ async (allMonsterMobIds: bigint[]): Promise => {
+ const _monsterTemplates: MonsterTemplate[] = await Promise.all(
+ allMonsterMobIds.map(async mobId => {
+ const mobData = getComponentValueStrict(
+ Mobs,
+ encodeEntity({ mobId: 'uint256' }, { mobId: BigInt(mobId) }),
+ );
+
+ const { mobMetadata: metadataURI, mobStats } = mobData;
+
+ const monsterStats = decodeMonsterStats(mobStats);
+
+ const fetachedMetadata = await fetchMetadataFromUri(
+ uriToHttp(metadataURI)[0],
+ );
+
+ return {
+ agility: monsterStats.agility.toString(),
+ baseHp: monsterStats.baseHp.toString(),
+ currentHp: monsterStats.currentHp.toString(),
+ entityClass: monsterStats.entityClass,
+ experience: monsterStats.experience.toString(),
+ intelligence: monsterStats.intelligence.toString(),
+ level: monsterStats.level.toString(),
+ mobId: mobId.toString(),
+ strength: monsterStats.strength.toString(),
+ ...fetachedMetadata,
+ } as MonsterTemplate;
+ }),
+ );
+
+ return _monsterTemplates;
+ },
+ [Mobs],
+ );
+
+ useEffect(() => {
+ (async () => {
+ if (!isSynced) return;
+
+ try {
+ const allMonsterMobIds = Array.from(
+ runQuery([Has(Mobs), HasValue(Mobs, { mobType: MobType.Monster })]),
+ ).map(entity => {
+ const { mobId } = decodeEntity({ mobId: 'uint256' }, entity);
+ return mobId;
+ });
+
+ if (allMonsterMobIds.length > 0) {
+ const _monsterTemplates =
+ await fetchMonsterTemplates(allMonsterMobIds);
+ setMonsterTemplates(_monsterTemplates);
+ }
+ } catch (e) {
+ renderError(
+ (e as Error)?.message ?? 'Failed to fetch monster templates.',
+ e,
+ );
+ } finally {
+ setIsLoading(false);
+ }
+ })();
+ }, [fetchMonsterTemplates, isSynced, Mobs, renderError]);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useMonsters = (): MonstersContextType =>
+ useContext(MonstersContext);
diff --git a/packages/client/src/index.tsx b/packages/client/src/index.tsx
index c72e546ce..f673a69e2 100644
--- a/packages/client/src/index.tsx
+++ b/packages/client/src/index.tsx
@@ -15,6 +15,7 @@ import { App } from './App';
import { DevTools } from './components/DevTools';
import { CharacterProvider } from './contexts/CharacterContext';
import { ItemsProvider } from './contexts/ItemsContext';
+import { MonstersProvider } from './contexts/MonstersContext';
import { MUDProvider } from './contexts/MUDContext';
import { Web3Provider } from './contexts/Web3Provider';
import { setup } from './lib/mud/setup';
@@ -32,9 +33,11 @@ setup().then(async result => {
-
-
-
+
+
+
+
+
{import.meta.env.DEV && }
diff --git a/packages/client/src/utils/helpers.ts b/packages/client/src/utils/helpers.ts
index 3edb3854b..8ee9364e1 100644
--- a/packages/client/src/utils/helpers.ts
+++ b/packages/client/src/utils/helpers.ts
@@ -1,6 +1,11 @@
import { decodeAbiParameters, hexToBigInt } from 'viem';
-import { type ArmorStats, type Metadata, WeaponStats } from '../utils/types';
+import {
+ type ArmorStats,
+ type EntityStats,
+ type Metadata,
+ type WeaponStats,
+} from '../utils/types';
export const decodeArmorStats = (statsBytes: string): ArmorStats => {
const itemTemplateStats = decodeAbiParameters(
@@ -81,6 +86,41 @@ export const decodeMonsterId = (
return { mobId: mobIdBigInt.toString() };
};
+export const decodeMonsterStats = (statsBytes: string): EntityStats => {
+ const monsterTemplateStats = decodeAbiParameters(
+ [
+ {
+ name: 'monsterStats',
+ type: 'tuple',
+ components: [
+ { name: 'actions', type: 'bytes32[]' },
+ { name: 'agility', type: 'uint256' },
+ { name: 'armor', type: 'uint256' },
+ { name: 'class', type: 'uint8' },
+ { name: 'experience', type: 'uint256' },
+ { name: 'hitPoints', type: 'uint256' },
+ { name: 'intelligence', type: 'uint256' },
+ { name: 'inventory', type: 'uint256[]' },
+ { name: 'level', type: 'uint256' },
+ { name: 'strength', type: 'uint256' },
+ ],
+ },
+ ],
+ statsBytes as `0x${string}`,
+ )[0];
+
+ return {
+ agility: monsterTemplateStats.agility.toString(),
+ baseHp: monsterTemplateStats.hitPoints.toString(),
+ currentHp: monsterTemplateStats.hitPoints.toString(),
+ entityClass: monsterTemplateStats.class,
+ experience: monsterTemplateStats.experience.toString(),
+ intelligence: monsterTemplateStats.intelligence.toString(),
+ level: monsterTemplateStats.level.toString(),
+ strength: monsterTemplateStats.strength.toString(),
+ };
+};
+
export const decodeWeaponStats = (statsBytes: string): WeaponStats => {
const itemTemplateStats = decodeAbiParameters(
[
diff --git a/packages/client/src/utils/types.ts b/packages/client/src/utils/types.ts
index f8fae2e63..7ce464035 100644
--- a/packages/client/src/utils/types.ts
+++ b/packages/client/src/utils/types.ts
@@ -21,6 +21,11 @@ export enum ItemType {
QuestItem,
}
+export enum MobType {
+ Monster,
+ NPC,
+}
+
export enum StatsClasses {
Warrior,
Rogue,
@@ -115,10 +120,15 @@ export type Metadata = {
name: string;
};
-export type Monster = Metadata &
- EntityStats & {
- id: Entity;
- inBattle: boolean;
+export type Monster = MonsterTemplate & {
+ id: Entity;
+ inBattle: boolean;
+ isSpawned: boolean;
+ position: { x: number; y: number };
+};
+
+export type MonsterTemplate = EntityStats &
+ Metadata & {
mobId: string;
};
From d4254b894c492b1ae9c6e4bf821a0234c57cb06a Mon Sep 17 00:00:00 2001
From: ECWireless
Date: Tue, 27 Aug 2024 09:01:09 -0600
Subject: [PATCH 2/2] Add an armor and template type
---
packages/client/src/contexts/ItemsContext.tsx | 41 +++++--------------
.../client/src/pages/CharacterCreation.tsx | 30 ++++++++++----
packages/client/src/utils/types.ts | 28 ++++++-------
3 files changed, 48 insertions(+), 51 deletions(-)
diff --git a/packages/client/src/contexts/ItemsContext.tsx b/packages/client/src/contexts/ItemsContext.tsx
index 85162a87e..a55afcc3c 100644
--- a/packages/client/src/contexts/ItemsContext.tsx
+++ b/packages/client/src/contexts/ItemsContext.tsx
@@ -12,7 +12,6 @@ import {
useEffect,
useState,
} from 'react';
-import { zeroAddress } from 'viem';
import { useToast } from '../hooks/useToast';
import {
@@ -21,12 +20,16 @@ import {
fetchMetadataFromUri,
uriToHttp,
} from '../utils/helpers';
-import { type Armor, ItemType, type Weapon } from '../utils/types';
+import {
+ type ArmorTemplate,
+ ItemType,
+ type WeaponTemplate,
+} from '../utils/types';
import { useMUD } from './MUDContext';
type ItemsContextType = {
- armorTemplates: Armor[];
- weaponTemplates: Weapon[];
+ armorTemplates: ArmorTemplate[];
+ weaponTemplates: WeaponTemplate[];
isLoading: boolean;
};
@@ -47,22 +50,14 @@ export const ItemsProvider = ({
isSynced,
} = useMUD();
- const [armorTemplates, setArmorTemplates] = useState([]);
- const [weaponTemplates, setWeaponTemplates] = useState([]);
+ const [armorTemplates, setArmorTemplates] = useState([]);
+ const [weaponTemplates, setWeaponTemplates] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const fetchAllArmor = useCallback(
async (allArmorIds: bigint[]) => {
const fullArmor = await Promise.all(
allArmorIds.map(async armorId => {
- const tokenOwnersEntity = encodeEntity(
- { owner: 'address', tokenId: 'uint256' },
- {
- owner: zeroAddress,
- tokenId: armorId,
- },
- );
-
const tokenIdEntity = encodeEntity(
{ tokenId: 'uint256' },
{ tokenId: armorId },
@@ -89,12 +84,9 @@ export const ItemsProvider = ({
...metadata,
agiModifier: decodedArmorStats.agiModifier,
armorModifier: decodedArmorStats.armorModifier,
- balance: '0',
hitPointModifier: decodedArmorStats.hitPointModifier,
intModifier: decodedArmorStats.intModifier,
- itemId: tokenOwnersEntity,
minLevel: decodedArmorStats.minLevel,
- owner: zeroAddress,
statRestrictions: {
minAgility: decodedArmorStats.statRestrictions.minAgility,
minIntelligence:
@@ -103,7 +95,7 @@ export const ItemsProvider = ({
},
strModifier: decodedArmorStats.strModifier,
tokenId: armorId.toString(),
- } as Armor;
+ } as ArmorTemplate;
}),
);
@@ -116,14 +108,6 @@ export const ItemsProvider = ({
async (allWeaponIds: bigint[]) => {
const fullWeapons = await Promise.all(
allWeaponIds.map(async weaponId => {
- const tokenOwnersEntity = encodeEntity(
- { owner: 'address', tokenId: 'uint256' },
- {
- owner: zeroAddress,
- tokenId: weaponId,
- },
- );
-
const tokenIdEntity = encodeEntity(
{ tokenId: 'uint256' },
{ tokenId: weaponId },
@@ -149,14 +133,11 @@ export const ItemsProvider = ({
return {
...metadata,
agiModifier: decodedArmorStats.agiModifier,
- balance: '0',
hitPointModifier: decodedArmorStats.hitPointModifier,
intModifier: decodedArmorStats.intModifier,
- itemId: tokenOwnersEntity,
maxDamage: decodedArmorStats.maxDamage,
minDamage: decodedArmorStats.minDamage,
minLevel: decodedArmorStats.minLevel,
- owner: zeroAddress,
statRestrictions: {
minAgility: decodedArmorStats.statRestrictions.minAgility,
minIntelligence:
@@ -165,7 +146,7 @@ export const ItemsProvider = ({
},
strModifier: decodedArmorStats.strModifier,
tokenId: weaponId.toString(),
- } as Weapon;
+ } as WeaponTemplate;
}),
);
diff --git a/packages/client/src/pages/CharacterCreation.tsx b/packages/client/src/pages/CharacterCreation.tsx
index 9c5a26a6b..3e5fb93b6 100644
--- a/packages/client/src/pages/CharacterCreation.tsx
+++ b/packages/client/src/pages/CharacterCreation.tsx
@@ -17,11 +17,17 @@ import {
VStack,
} from '@chakra-ui/react';
import { useComponentValue } from '@latticexyz/react';
-import { getComponentValueStrict, Has, runQuery } from '@latticexyz/recs';
+import {
+ Entity,
+ getComponentValueStrict,
+ Has,
+ runQuery,
+} from '@latticexyz/recs';
import { singletonEntity } from '@latticexyz/store-sync/recs';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { FaLock } from 'react-icons/fa';
import { useNavigate } from 'react-router-dom';
+import { zeroAddress, zeroHash } from 'viem';
import { useAccount } from 'wagmi';
import { ItemCardSmall } from '../components/ItemCard';
@@ -99,12 +105,22 @@ export const CharacterCreation = (): JSX.Element => {
item[1].toString(),
);
- const _starterArmor = armorTemplates.filter(armor =>
- starterArmorTokenIds.includes(armor.tokenId),
- );
- const _starterWeapons = weaponTemplates.filter(weapon =>
- starterWeaponTokenIds.includes(weapon.tokenId),
- );
+ const _starterArmor = armorTemplates
+ .filter(armor => starterArmorTokenIds.includes(armor.tokenId))
+ .map(armor => ({
+ ...armor,
+ balance: '1',
+ itemId: zeroHash as Entity,
+ owner: zeroAddress,
+ }));
+ const _starterWeapons = weaponTemplates
+ .filter(weapon => starterWeaponTokenIds.includes(weapon.tokenId))
+ .map(armor => ({
+ ...armor,
+ balance: '1',
+ itemId: zeroHash as Entity,
+ owner: zeroAddress,
+ }));
setStarterArmor(_starterArmor);
setStarterWeapons(_starterWeapons);
diff --git a/packages/client/src/utils/types.ts b/packages/client/src/utils/types.ts
index 7ce464035..ea485b860 100644
--- a/packages/client/src/utils/types.ts
+++ b/packages/client/src/utils/types.ts
@@ -51,13 +51,11 @@ export type ActionOutcomeType = {
weaponId: string;
};
-export type Armor = ArmorStats &
- Metadata & {
- balance: string;
- itemId: Entity;
- owner: string;
- tokenId: string;
- };
+export type Armor = ArmorTemplate & {
+ balance: string;
+ itemId: Entity;
+ owner: string;
+};
export type ArmorStats = {
agiModifier: string;
@@ -69,6 +67,8 @@ export type ArmorStats = {
strModifier: string;
};
+export type ArmorTemplate = ArmorStats & Metadata & { tokenId: string };
+
export type Character = CharacterData & EntityStats & Metadata;
export type CharacterData = {
@@ -132,13 +132,11 @@ export type MonsterTemplate = EntityStats &
mobId: string;
};
-export type Weapon = WeaponStats &
- Metadata & {
- balance: string;
- itemId: Entity;
- owner: string;
- tokenId: string;
- };
+export type Weapon = WeaponTemplate & {
+ balance: string;
+ itemId: Entity;
+ owner: string;
+};
export type WeaponStats = {
agiModifier: string;
@@ -151,6 +149,8 @@ export type WeaponStats = {
strModifier: string;
};
+export type WeaponTemplate = WeaponStats & Metadata & { tokenId: string };
+
export type Item = Metadata & {
itemId: Entity;
itemType: ItemType;