diff --git a/ecs/Bicho.ts b/ecs/Bicho.ts index 3473f18..35dc0ef 100644 --- a/ecs/Bicho.ts +++ b/ecs/Bicho.ts @@ -15,12 +15,41 @@ interface UpdateEvent { rotation?: ReadOnlyVector3; } +export enum BichoType { + Avestruz, + Águia, + Burro, + Borboleta, + Cachorro, + Cabra, + Carneiro, + Camelo, + Cobra, + Coelho, + Cavalo, + Elefante, + Galo, + Gato, + Jacaré, + Leão, + Macaco, + Porco, + Pavão, + Peru, + Touro, + Tigre, + Urso, + Veado, + Vaca, + COUNT, +} + export default class Bicho extends NPC { static contract: any; address: string; - id: number; + type: BichoType; bus: MessageBus; @@ -30,17 +59,18 @@ export default class Bicho extends NPC { constructor( address: string, - id: number, + type: BichoType, bus: MessageBus, transformArgs: TransformConstructorArgs, remote = false, ) { - super(transformArgs, placeholder, () => {}); + super(transformArgs, placeholder, () => {}, + { onlyClickTrigger: true, onlyETrigger: true, walkingAnim: 'Walk' }); this.address = address; - this.id = id; + this.type = type; this.bus = bus; this.remote = remote; - this.eventId = `${this.address}[${this.id}]`; + this.eventId = `${this.address}[${this.type}]`; this.bus.on(this.eventId, (value) => this.update(value)); } @@ -49,11 +79,11 @@ export default class Bicho extends NPC { } update({ position, rotation }: UpdateEvent) { - if (!this.remote) this.bus.emit('bicho', { address: this.address, id: this.id }); + if (!this.remote) this.bus.emit('bicho', { address: this.address, type: this.type }); const transform = this.getComponent(Transform); if (rotation) transform.rotation.setEuler(0, rotation.y, 0); if (position) { - const offset = this.id % 2 ? 1 : -1; + const offset = this.type % 2 ? 1 : -1; transform.position.set(position.x, position.y, position.z + offset); } } diff --git a/ecs/SceneManager.ts b/ecs/SceneManager.ts index a84dfd0..e05a21a 100644 --- a/ecs/SceneManager.ts +++ b/ecs/SceneManager.ts @@ -5,8 +5,9 @@ import { ISystem, MessageBus, } from 'decentraland-ecs'; -import Bicho from './Bicho'; -import getUserBichos from './utils/getUserBichos'; +import Bicho, { BichoType } from './Bicho'; +import getUserAddress from './web3/getUserAddress'; +import getUserBichos from './web3/getUserBichos'; declare const dcl: DecentralandInterface; @@ -15,13 +16,13 @@ interface BaseEvent { } interface BichoEvent extends BaseEvent { - id: number; + type: BichoType; } export default class SceneManager implements ISystem { bus = new MessageBus(); - bichos = {} as Record>; + bichos: { [address: string]: { [T in BichoType]?: Bicho } } = {}; engine: IEngine; @@ -35,12 +36,12 @@ export default class SceneManager implements ISystem { dcl.onEvent((event) => this.onDCLEvent(event)); this.bus.on('request', () => this.onRequest()); - this.bus.on('bicho', ({ address, id }: BichoEvent) => this.onBicho(address, id)); + this.bus.on('bicho', ({ address, type }: BichoEvent) => this.onBicho(address, type)); this.bus.on('deactivate', ({ address }: BaseEvent) => this.onDeactivate(address)); this.bus.emit('request', null); - getUserBichos().then(({ address, bichos }) => { + Promise.all([getUserAddress(), getUserBichos()]).then(([address, bichos]) => { this.address = address; - bichos.forEach((id) => this.bus.emit('bicho', { address, id } as BichoEvent)); + bichos?.forEach((type) => this.bus.emit('bicho', { address, type } as BichoEvent)); }); } @@ -53,18 +54,18 @@ export default class SceneManager implements ISystem { Object.values(this.bichos[this.address]).forEach((bicho) => bicho.onDCLEvent(event)); } - onBicho(address: string, id: number) { + onBicho(address: string, type: BichoType) { this.bichos[address] ??= {}; - if (this.bichos[address][id]) return; - const bicho = new Bicho(address, id, this.bus, {}, address !== this.address); + if (this.bichos[address][type]) return; + const bicho = new Bicho(address, type, this.bus, {}, address !== this.address); this.engine.addEntity(bicho); - this.bichos[address][id] = bicho; + this.bichos[address][type] = bicho; } onRequest() { if (!this.address || !this.bichos[this.address]) return; - Object.keys(this.bichos[this.address]).forEach((id) => this.bus.emit('bicho', - { address: this.address, id: Number(id) } as BichoEvent)); + Object.keys(this.bichos[this.address]).forEach((type) => this.bus.emit('bicho', + { address: this.address, type: Number(type) } as BichoEvent)); } onDeactivate(address: string) { diff --git a/ecs/utils/getRequestManager.ts b/ecs/utils/getRequestManager.ts deleted file mode 100644 index b613d13..0000000 --- a/ecs/utils/getRequestManager.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { DecentralandInterface } from 'decentraland-ecs'; -import { RequestManager } from 'eth-connect'; - -declare const dcl: DecentralandInterface; - -let requestManager: RequestManager = null; - -export default async () => { - requestManager ??= new RequestManager(await dcl - .callRpc((await dcl.loadModule('web3-provider')).rpcHandle, 'getProvider', [])); - return requestManager; -}; diff --git a/ecs/utils/getUserAddress.ts b/ecs/utils/getUserAddress.ts deleted file mode 100644 index 654221f..0000000 --- a/ecs/utils/getUserAddress.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { DecentralandInterface } from 'decentraland-ecs'; - -declare const dcl: DecentralandInterface; - -let address: string = null; - -export default async () => { - address ??= await dcl - .callRpc((await dcl.loadModule('Identity')).rpcHandle, 'getUserPublicKey', []); - return address; -}; diff --git a/ecs/utils/getUserBichos.ts b/ecs/utils/getUserBichos.ts deleted file mode 100644 index 237b088..0000000 --- a/ecs/utils/getUserBichos.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { BigNumber, ContractFactory } from 'eth-connect'; -import BichoABI from '../../abi/Bicho.json'; -import getUserAddress from './getUserAddress'; -import getRequestManager from './getRequestManager'; - -declare const BICHO_ADDRESS: string; - -let contract: any = null; - -export default async () => { - const [address, requestManager] = await Promise.all([getUserAddress(), getRequestManager()]); - if (!address) return { address: null, bichos: [] }; - contract ??= await new ContractFactory(requestManager, BichoABI).at(BICHO_ADDRESS); - const balances: BigNumber[] = await contract.balanceOfBatch( - Array(25).fill(address), - Array(25).fill(null).map((_, i) => i), - ); - return { - address, - bichos: balances - .map((balance, id) => ({ id, balance })) - .filter(({ balance }) => !balance.isZero()) - .map(({ id }) => id), - }; -}; diff --git a/ecs/web3/getBichoContract.ts b/ecs/web3/getBichoContract.ts new file mode 100644 index 0000000..a0f41de --- /dev/null +++ b/ecs/web3/getBichoContract.ts @@ -0,0 +1,18 @@ +import { Contract } from '@ethersproject/contracts'; +import { Bicho as BichoContract } from '../../abi/types/Bicho'; +import BichoABI from '../../abi/Bicho.json'; +import getProvider from './getProvider'; + +declare const BICHO_ADDRESS: string; + +let contract: Promise; + +const getContract = async () => { + const provider = await getProvider(); + return new Contract(BICHO_ADDRESS, BichoABI, provider) as BichoContract; +}; + +export default async () => { + contract ??= getContract(); + return contract; +}; diff --git a/ecs/web3/getProvider.ts b/ecs/web3/getProvider.ts new file mode 100644 index 0000000..e766013 --- /dev/null +++ b/ecs/web3/getProvider.ts @@ -0,0 +1,23 @@ +import { DecentralandInterface } from 'decentraland-ecs'; +import { Web3Provider, TransactionResponse } from '@ethersproject/providers'; + +declare const dcl: DecentralandInterface; + +class DCLProvider extends Web3Provider { + // eslint-disable-next-line class-methods-use-this + async getTransaction(hash: string | Promise) { + return { hash: await hash } as TransactionResponse; + } +} + +let provider: Promise; + +const getProvider = async () => { + const { rpcHandle } = await dcl.loadModule('web3-provider'); + return new DCLProvider(await dcl.callRpc(rpcHandle, 'getProvider', [])); +}; + +export default async () => { + provider ??= getProvider(); + return provider; +}; diff --git a/ecs/web3/getUserAddress.ts b/ecs/web3/getUserAddress.ts new file mode 100644 index 0000000..426975b --- /dev/null +++ b/ecs/web3/getUserAddress.ts @@ -0,0 +1,15 @@ +import { DecentralandInterface } from 'decentraland-ecs'; + +declare const dcl: DecentralandInterface; + +let address: Promise; + +const getAddress = async () => { + const { rpcHandle } = await dcl.loadModule('Identity'); + return await dcl.callRpc(rpcHandle, 'getUserPublicKey', []) as string; +}; + +export default async () => { + address ??= getAddress(); + return address; +}; diff --git a/ecs/web3/getUserBichos.ts b/ecs/web3/getUserBichos.ts new file mode 100644 index 0000000..d920033 --- /dev/null +++ b/ecs/web3/getUserBichos.ts @@ -0,0 +1,16 @@ +import { BichoType } from '../Bicho'; +import getBichoContract from './getBichoContract'; +import getUserAddress from './getUserAddress'; + +export default async () => { + const [address, contract] = await Promise.all([getUserAddress(), getBichoContract()]); + if (!address) return null; + const balances = await contract.balanceOfBatch( + Array(25).fill(address), + Array(25).fill(null).map((_, i) => i), + ); + return balances + .map((balance, id) => ({ id, balance })) + .filter(({ balance }) => !balance.isZero()) + .map(({ id }) => id % BichoType.COUNT as BichoType); +};