From 884642a06930aee2e446a6b0624a849087049cad Mon Sep 17 00:00:00 2001 From: Kevin Ingersoll Date: Tue, 5 Mar 2024 11:34:35 +0000 Subject: [PATCH] test: set up mock game for test data, use in zustand tests (#2361) --- packages/store-sync/package.json | 2 + .../src/zustand/createStorageAdapter.test.ts | 190 ++++++++--- packages/store-sync/test/common.ts | 18 + packages/store-sync/test/deployMockGame.ts | 33 ++ packages/store-sync/test/globalSetup.ts | 16 + packages/store-sync/vitest.config.ts | 7 + pnpm-lock.yaml | 97 +++++- pnpm-workspace.yaml | 1 + test/README.md | 3 + test/mock-game-contracts/.gitignore | 10 + test/mock-game-contracts/.solhint.json | 11 + test/mock-game-contracts/foundry.toml | 24 ++ test/mock-game-contracts/mud.config.ts | 61 ++++ test/mock-game-contracts/package.json | 23 ++ test/mock-game-contracts/remappings.txt | 3 + .../script/PostDeploy.s.sol | 39 +++ .../src/codegen/common.sol | 10 + .../mock-game-contracts/src/codegen/index.sol | 11 + .../src/codegen/tables/Health.sol | 199 +++++++++++ .../src/codegen/tables/Inventory.sol | 211 ++++++++++++ .../src/codegen/tables/Position.sol | 318 ++++++++++++++++++ .../src/codegen/tables/Score.sol | 211 ++++++++++++ .../src/codegen/tables/Terrain.sol | 214 ++++++++++++ .../src/codegen/tables/Winner.sol | 199 +++++++++++ .../src/codegen/world/IWorld.sol | 15 + test/mock-game-contracts/tsconfig.json | 13 + 26 files changed, 1893 insertions(+), 46 deletions(-) create mode 100644 packages/store-sync/test/common.ts create mode 100644 packages/store-sync/test/deployMockGame.ts create mode 100644 packages/store-sync/test/globalSetup.ts create mode 100644 packages/store-sync/vitest.config.ts create mode 100644 test/README.md create mode 100644 test/mock-game-contracts/.gitignore create mode 100644 test/mock-game-contracts/.solhint.json create mode 100644 test/mock-game-contracts/foundry.toml create mode 100644 test/mock-game-contracts/mud.config.ts create mode 100644 test/mock-game-contracts/package.json create mode 100644 test/mock-game-contracts/remappings.txt create mode 100644 test/mock-game-contracts/script/PostDeploy.s.sol create mode 100644 test/mock-game-contracts/src/codegen/common.sol create mode 100644 test/mock-game-contracts/src/codegen/index.sol create mode 100644 test/mock-game-contracts/src/codegen/tables/Health.sol create mode 100644 test/mock-game-contracts/src/codegen/tables/Inventory.sol create mode 100644 test/mock-game-contracts/src/codegen/tables/Position.sol create mode 100644 test/mock-game-contracts/src/codegen/tables/Score.sol create mode 100644 test/mock-game-contracts/src/codegen/tables/Terrain.sol create mode 100644 test/mock-game-contracts/src/codegen/tables/Winner.sol create mode 100644 test/mock-game-contracts/src/codegen/world/IWorld.sol create mode 100644 test/mock-game-contracts/tsconfig.json diff --git a/packages/store-sync/package.json b/packages/store-sync/package.json index b6ce955f59..06b3bfb507 100644 --- a/packages/store-sync/package.json +++ b/packages/store-sync/package.json @@ -83,6 +83,8 @@ "devDependencies": { "@types/debug": "^4.1.7", "@types/sql.js": "^1.4.4", + "@viem/anvil": "^0.0.7", + "mock-game-contracts": "workspace:*", "tsup": "^6.7.0", "vitest": "0.34.6" }, diff --git a/packages/store-sync/src/zustand/createStorageAdapter.test.ts b/packages/store-sync/src/zustand/createStorageAdapter.test.ts index cdc089d051..e6a844675d 100644 --- a/packages/store-sync/src/zustand/createStorageAdapter.test.ts +++ b/packages/store-sync/src/zustand/createStorageAdapter.test.ts @@ -1,71 +1,173 @@ import { describe, expect, it } from "vitest"; -import mudConfig from "../../../../e2e/packages/contracts/mud.config"; -import worldRpcLogs from "../../../../test-data/world-logs.json"; -import { groupLogsByBlockNumber } from "@latticexyz/block-logs-stream"; -import { StoreEventsLog } from "../common"; -import { RpcLog, formatLog, decodeEventLog, Hex } from "viem"; -import { resolveConfig, storeEventsAbi } from "@latticexyz/store"; +import { storeEventsAbi } from "@latticexyz/store"; import { createStorageAdapter } from "./createStorageAdapter"; import { createStore } from "./createStore"; +import { config, deployMockGame } from "../../test/deployMockGame"; +import { fetchAndStoreLogs } from "../fetchAndStoreLogs"; +import { publicClient } from "../../test/common"; -const tables = resolveConfig(mudConfig).tables; +describe("createStorageAdapter", async () => { + await deployMockGame(); -// TODO: make test-data a proper package and export this -const blocks = groupLogsByBlockNumber( - worldRpcLogs.map((log) => { - const { eventName, args } = decodeEventLog({ - abi: storeEventsAbi, - data: log.data as Hex, - topics: log.topics as [Hex, ...Hex[]], - strict: true, - }); - return formatLog(log as unknown as RpcLog, { args, eventName: eventName as string }) as StoreEventsLog; - }), -); - -describe("createStorageAdapter", () => { it("sets component values from logs", async () => { - const useStore = createStore({ tables }); + const useStore = createStore({ tables: config.tables }); const storageAdapter = createStorageAdapter({ store: useStore }); - for (const block of blocks) { - await storageAdapter(block); + console.log("fetching blocks"); + for await (const block of fetchAndStoreLogs({ + storageAdapter, + publicClient, + events: storeEventsAbi, + fromBlock: 0n, + toBlock: await publicClient.getBlockNumber(), + })) { + // console.log("got block", block.blockNumber); } - expect(useStore.getState().getRecords(tables.NumberList)).toMatchInlineSnapshot(` + expect(useStore.getState().getRecords(config.tables.Position)).toMatchInlineSnapshot(` { - "0x746200000000000000000000000000004e756d6265724c697374000000000000:0x": { - "id": "0x746200000000000000000000000000004e756d6265724c697374000000000000:0x", - "key": {}, - "keyTuple": [], + "0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x000000000000000000000000078cf0753dd50f7c56f20b3ae02719ea199be2eb": { + "id": "0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x000000000000000000000000078cf0753dd50f7c56f20b3ae02719ea199be2eb", + "key": { + "player": "0x078cf0753dd50f7C56F20B3Ae02719EA199BE2eb", + }, + "keyTuple": [ + "0x000000000000000000000000078cf0753dd50f7c56f20b3ae02719ea199be2eb", + ], + "table": { + "keySchema": { + "player": { + "internalType": "address", + "type": "address", + }, + }, + "name": "Position", + "namespace": "", + "tableId": "0x74620000000000000000000000000000506f736974696f6e0000000000000000", + "valueSchema": { + "x": { + "internalType": "int32", + "type": "int32", + }, + "y": { + "internalType": "int32", + "type": "int32", + }, + }, + }, + "value": { + "x": 3, + "y": 5, + }, + }, + "0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x0000000000000000000000001d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e": { + "id": "0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x0000000000000000000000001d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", + "key": { + "player": "0x1D96F2f6BeF1202E4Ce1Ff6Dad0c2CB002861d3e", + }, + "keyTuple": [ + "0x0000000000000000000000001d96f2f6bef1202e4ce1ff6dad0c2cb002861d3e", + ], + "table": { + "keySchema": { + "player": { + "internalType": "address", + "type": "address", + }, + }, + "name": "Position", + "namespace": "", + "tableId": "0x74620000000000000000000000000000506f736974696f6e0000000000000000", + "valueSchema": { + "x": { + "internalType": "int32", + "type": "int32", + }, + "y": { + "internalType": "int32", + "type": "int32", + }, + }, + }, + "value": { + "x": 1, + "y": -1, + }, + }, + "0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x000000000000000000000000328809bc894f92807417d2dad6b7c998c1afdac6": { + "id": "0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x000000000000000000000000328809bc894f92807417d2dad6b7c998c1afdac6", + "key": { + "player": "0x328809Bc894f92807417D2dAD6b7C998c1aFdac6", + }, + "keyTuple": [ + "0x000000000000000000000000328809bc894f92807417d2dad6b7c998c1afdac6", + ], + "table": { + "keySchema": { + "player": { + "internalType": "address", + "type": "address", + }, + }, + "name": "Position", + "namespace": "", + "tableId": "0x74620000000000000000000000000000506f736974696f6e0000000000000000", + "valueSchema": { + "x": { + "internalType": "int32", + "type": "int32", + }, + "y": { + "internalType": "int32", + "type": "int32", + }, + }, + }, + "value": { + "x": 3, + "y": 5, + }, + }, + "0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x000000000000000000000000dba86119a787422c593cef119e40887f396024e2": { + "id": "0x74620000000000000000000000000000506f736974696f6e0000000000000000:0x000000000000000000000000dba86119a787422c593cef119e40887f396024e2", + "key": { + "player": "0xdBa86119a787422C593ceF119E40887f396024E2", + }, + "keyTuple": [ + "0x000000000000000000000000dba86119a787422c593cef119e40887f396024e2", + ], "table": { - "keySchema": {}, - "name": "NumberList", + "keySchema": { + "player": { + "internalType": "address", + "type": "address", + }, + }, + "name": "Position", "namespace": "", - "tableId": "0x746200000000000000000000000000004e756d6265724c697374000000000000", + "tableId": "0x74620000000000000000000000000000506f736974696f6e0000000000000000", "valueSchema": { - "value": { - "internalType": "uint32[]", - "type": "uint32[]", + "x": { + "internalType": "int32", + "type": "int32", + }, + "y": { + "internalType": "int32", + "type": "int32", }, }, }, "value": { - "value": [ - 420, - 69, - ], + "x": 100, + "y": 100, }, }, } `); - expect(useStore.getState().getValue(tables.NumberList, {})).toMatchInlineSnapshot(` + expect(useStore.getState().getValue(config.tables.Terrain, { x: 3, y: 5 })).toMatchInlineSnapshot(` { - "value": [ - 420, - 69, - ], + "terrainType": 2, } `); }); diff --git a/packages/store-sync/test/common.ts b/packages/store-sync/test/common.ts new file mode 100644 index 0000000000..62b6bc70f1 --- /dev/null +++ b/packages/store-sync/test/common.ts @@ -0,0 +1,18 @@ +import { createPublicClient, createTestClient, http } from "viem"; + +export const anvilHost = "127.0.0.1"; +export const anvilPort = 8555; + +// ID of the current test worker. Used by the `@viem/anvil` proxy server. +export const poolId = Number(process.env.VITEST_POOL_ID ?? 1); + +export const anvilRpcUrl = `http://${anvilHost}:${anvilPort}/${poolId}`; + +export const testClient = createTestClient({ + mode: "anvil", + transport: http(anvilRpcUrl), +}); + +export const publicClient = createPublicClient({ + transport: http(anvilRpcUrl), +}); diff --git a/packages/store-sync/test/deployMockGame.ts b/packages/store-sync/test/deployMockGame.ts new file mode 100644 index 0000000000..99bf103743 --- /dev/null +++ b/packages/store-sync/test/deployMockGame.ts @@ -0,0 +1,33 @@ +import { execa } from "execa"; +import { anvilRpcUrl, testClient } from "./common"; +import mudConfig from "mock-game-contracts/mud.config"; +import { resolveConfig } from "@latticexyz/store"; + +export const config = resolveConfig(mudConfig); + +export async function deployMockGame(): Promise { + const automine = await testClient.getAutomine(); + + if (!automine) { + console.log("turning on automine for deploy"); + await testClient.setAutomine(true); + } + + // TODO: build in globalSetup so we don't have to build here? + console.log("deploying mud"); + const { stdout, stderr } = await execa("pnpm", ["mud", "deploy", "--rpc", anvilRpcUrl, "--saveDeployment", "false"], { + cwd: `${__dirname}/../../../test/mock-game-contracts`, + env: { + // anvil default account + PRIVATE_KEY: "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + DEBUG: "mud:*", + }, + }); + if (stderr) console.error(stderr); + if (stdout) console.log(stdout); + + if (!automine) { + console.log("turning off automine"); + await testClient.setAutomine(false); + } +} diff --git a/packages/store-sync/test/globalSetup.ts b/packages/store-sync/test/globalSetup.ts new file mode 100644 index 0000000000..dd8ed21839 --- /dev/null +++ b/packages/store-sync/test/globalSetup.ts @@ -0,0 +1,16 @@ +import { startProxy as startAnvilProxy } from "@viem/anvil"; +import { anvilHost, anvilPort } from "./common"; + +export default async function globalSetup(): Promise<() => Promise> { + const shutdownAnvilProxy = await startAnvilProxy({ + host: anvilHost, + port: anvilPort, + options: { + noMining: true, + }, + }); + + return async () => { + await shutdownAnvilProxy(); + }; +} diff --git a/packages/store-sync/vitest.config.ts b/packages/store-sync/vitest.config.ts new file mode 100644 index 0000000000..1628ff996c --- /dev/null +++ b/packages/store-sync/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + globalSetup: ["test/globalSetup.ts"], + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 32fd2a7753..953183f71d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -965,6 +965,12 @@ importers: '@types/sql.js': specifier: ^1.4.4 version: 1.4.4 + '@viem/anvil': + specifier: ^0.0.7 + version: 0.0.7(debug@4.3.4) + mock-game-contracts: + specifier: workspace:* + version: link:../../test/mock-game-contracts tsup: specifier: ^6.7.0 version: 6.7.0(postcss@8.4.23)(typescript@5.1.6) @@ -1128,6 +1134,39 @@ importers: specifier: 0.34.6 version: 0.34.6(jsdom@22.1.0) + test/mock-game-contracts: + devDependencies: + '@latticexyz/cli': + specifier: link:../../packages/cli + version: link:../../packages/cli + '@latticexyz/schema-type': + specifier: link:../../packages/schema-type + version: link:../../packages/schema-type + '@latticexyz/store': + specifier: link:../../packages/store + version: link:../../packages/store + '@latticexyz/world': + specifier: link:../../packages/world + version: link:../../packages/world + dotenv: + specifier: ^16.0.3 + version: 16.0.3 + ds-test: + specifier: https://github.com/dapphub/ds-test.git#e282159d5170298eb2455a6c05280ab5a73a4ef0 + version: github.com/dapphub/ds-test/e282159d5170298eb2455a6c05280ab5a73a4ef0 + forge-std: + specifier: https://github.com/foundry-rs/forge-std.git#74cfb77e308dd188d2f58864aaf44963ae6b88b1 + version: github.com/foundry-rs/forge-std/74cfb77e308dd188d2f58864aaf44963ae6b88b1 + prettier: + specifier: ^2.6.2 + version: 2.8.4 + rimraf: + specifier: ^3.0.2 + version: 3.0.2 + typescript: + specifier: 5.1.6 + version: 5.1.6 + packages: /@adraffy/ens-normalize@1.10.0: @@ -3638,6 +3677,19 @@ packages: '@use-gesture/core': 10.2.9 dev: false + /@viem/anvil@0.0.7(debug@4.3.4): + resolution: {integrity: sha512-F+3ljCT1bEt8T4Fzm9gWpIgO3Dc7bzG1TtUtkStkJFMuummqZ8kvYc3UFMo5j3F51fSWZZvEkjs3+i7qf0AOqQ==} + dependencies: + execa: 7.2.0 + get-port: 6.1.2 + http-proxy: 1.18.1(debug@4.3.4) + ws: 8.13.0 + transitivePeerDependencies: + - bufferutil + - debug + - utf-8-validate + dev: true + /@vitejs/plugin-react@4.0.0(vite@4.3.6): resolution: {integrity: sha512-HX0XzMjL3hhOYm+0s95pb0Z7F8O81G7joUHgfDd/9J/ZZf5k4xX6QAMFkKsHFxaHlf6X7GD7+XuaZ66ULiJuhQ==} engines: {node: ^14.18.0 || >=16.0.0} @@ -5022,7 +5074,6 @@ packages: /dotenv@16.0.3: resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} engines: {node: '>=12'} - dev: false /dprint-node@1.0.7: resolution: {integrity: sha512-NTZOW9A7ipb0n7z7nC3wftvsbceircwVHSgzobJsEQa+7RnOMbhrfX5IflA6CtC4GA63DSAiHYXa4JKEy9F7cA==} @@ -5737,7 +5788,6 @@ packages: /eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} - dev: false /eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} @@ -5792,6 +5842,21 @@ packages: signal-exit: 3.0.7 strip-final-newline: 3.0.0 + /execa@7.2.0: + resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==} + engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 4.3.1 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.1.0 + onetime: 6.0.0 + signal-exit: 3.0.7 + strip-final-newline: 3.0.0 + dev: true + /execcli@5.0.6: resolution: {integrity: sha512-du+uy/Ew2P90PKjSHI89u/XuqVaBDzvaJ6ePn40JaOy7owFQNsYDbd5AoR5A559HEAb1i5HO22rJxtgVonf5Bg==} engines: {node: '>=8', npm: '>=4'} @@ -6075,6 +6140,18 @@ packages: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true + /follow-redirects@1.15.5(debug@4.3.4): + resolution: {integrity: sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dependencies: + debug: 4.3.4 + dev: true + /form-data@4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} @@ -6214,6 +6291,11 @@ packages: engines: {node: '>=8.0.0'} dev: true + /get-port@6.1.2: + resolution: {integrity: sha512-BrGGraKm2uPqurfGVj/z97/zv8dPleC6x9JBNRTrDNtCkkRF4rPwrQXFgL7+I+q8QSdU4ntLQX2D7KIxSy8nGw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + /get-stream@5.2.0: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} @@ -6485,6 +6567,17 @@ packages: transitivePeerDependencies: - supports-color + /http-proxy@1.18.1(debug@4.3.4): + resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} + engines: {node: '>=8.0.0'} + dependencies: + eventemitter3: 4.0.7 + follow-redirects: 1.15.5(debug@4.3.4) + requires-port: 1.0.0 + transitivePeerDependencies: + - debug + dev: true + /https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 924b55f42e..f55b4d0da7 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,2 +1,3 @@ packages: - packages/* + - test/* diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000000..a45b76dcbd --- /dev/null +++ b/test/README.md @@ -0,0 +1,3 @@ +# Test utils + +These are private packages used by our test suites, mostly for mocking data. diff --git a/test/mock-game-contracts/.gitignore b/test/mock-game-contracts/.gitignore new file mode 100644 index 0000000000..da6ec0e4dc --- /dev/null +++ b/test/mock-game-contracts/.gitignore @@ -0,0 +1,10 @@ +out/ +cache/ +node_modules/ +bindings/ +artifacts/ +broadcast/ + +# Ignore all MUD deploy artifacts +deploys +worlds.json* diff --git a/test/mock-game-contracts/.solhint.json b/test/mock-game-contracts/.solhint.json new file mode 100644 index 0000000000..cb52819591 --- /dev/null +++ b/test/mock-game-contracts/.solhint.json @@ -0,0 +1,11 @@ +{ + "extends": "solhint:recommended", + "rules": { + "compiler-version": ["error", ">=0.8.0"], + "avoid-low-level-calls": "off", + "no-inline-assembly": "off", + "func-visibility": ["warn", { "ignoreConstructors": true }], + "no-empty-blocks": "off", + "no-complex-fallback": "off" + } +} diff --git a/test/mock-game-contracts/foundry.toml b/test/mock-game-contracts/foundry.toml new file mode 100644 index 0000000000..e8a674b19f --- /dev/null +++ b/test/mock-game-contracts/foundry.toml @@ -0,0 +1,24 @@ +[profile.default] +solc = "0.8.24" +ffi = false +fuzz_runs = 256 +optimizer = true +optimizer_runs = 3000 +verbosity = 2 +src = "src" +test = "test" +out = "out" +allow_paths = [ + # pnpm symlinks to the project root's node_modules + "../../node_modules", + # we're also using linked mud packages from the monorepo + "../../../packages" +] +extra_output_files = [ + "abi", + "evm.bytecode" +] +fs_permissions = [{ access = "read", path = "./"}] + +[profile.lattice-testnet] +eth_rpc_url = "https://follower.testnet-chain.linfra.xyz" diff --git a/test/mock-game-contracts/mud.config.ts b/test/mock-game-contracts/mud.config.ts new file mode 100644 index 0000000000..e24a74e274 --- /dev/null +++ b/test/mock-game-contracts/mud.config.ts @@ -0,0 +1,61 @@ +import { mudConfig } from "@latticexyz/world/register"; + +export default mudConfig({ + enums: { + TerrainType: ["None", "Ocean", "Grassland", "Desert"], + }, + tables: { + Position: { + keySchema: { + player: "address", + }, + valueSchema: { + x: "int32", + y: "int32", + }, + }, + Health: { + keySchema: { + player: "address", + }, + valueSchema: { + health: "uint256", + }, + }, + Inventory: { + keySchema: { + player: "address", + item: "uint8", + }, + valueSchema: { + amount: "uint32", + }, + }, + Score: { + keySchema: { + player: "address", + game: "uint256", + }, + valueSchema: { + score: "uint256", + }, + }, + Winner: { + keySchema: { + game: "uint256", + }, + valueSchema: { + player: "address", + }, + }, + Terrain: { + keySchema: { + x: "int32", + y: "int32", + }, + valueSchema: { + terrainType: "TerrainType", + }, + }, + }, +}); diff --git a/test/mock-game-contracts/package.json b/test/mock-game-contracts/package.json new file mode 100644 index 0000000000..663990bcbd --- /dev/null +++ b/test/mock-game-contracts/package.json @@ -0,0 +1,23 @@ +{ + "name": "mock-game-contracts", + "version": "0.0.0", + "private": true, + "license": "MIT", + "scripts": { + "build": "mud build", + "clean": "forge clean && rimraf src/codegen", + "deploy:local": "mud deploy" + }, + "devDependencies": { + "@latticexyz/cli": "link:../../packages/cli", + "@latticexyz/schema-type": "link:../../packages/schema-type", + "@latticexyz/store": "link:../../packages/store", + "@latticexyz/world": "link:../../packages/world", + "dotenv": "^16.0.3", + "ds-test": "https://github.com/dapphub/ds-test.git#e282159d5170298eb2455a6c05280ab5a73a4ef0", + "forge-std": "https://github.com/foundry-rs/forge-std.git#74cfb77e308dd188d2f58864aaf44963ae6b88b1", + "prettier": "^2.6.2", + "rimraf": "^3.0.2", + "typescript": "5.1.6" + } +} diff --git a/test/mock-game-contracts/remappings.txt b/test/mock-game-contracts/remappings.txt new file mode 100644 index 0000000000..c4d992480e --- /dev/null +++ b/test/mock-game-contracts/remappings.txt @@ -0,0 +1,3 @@ +ds-test/=node_modules/ds-test/src/ +forge-std/=node_modules/forge-std/src/ +@latticexyz/=node_modules/@latticexyz/ diff --git a/test/mock-game-contracts/script/PostDeploy.s.sol b/test/mock-game-contracts/script/PostDeploy.s.sol new file mode 100644 index 0000000000..81c5d93e85 --- /dev/null +++ b/test/mock-game-contracts/script/PostDeploy.s.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +import { Script } from "forge-std/Script.sol"; +import { console } from "forge-std/console.sol"; +import { StoreSwitch } from "@latticexyz/store/src/StoreSwitch.sol"; +import { IWorld } from "../src/codegen/world/IWorld.sol"; + +import { Position, Health, Terrain } from "../src/codegen/index.sol"; +import { TerrainType } from "../src/codegen/common.sol"; + +contract PostDeploy is Script { + function run(address worldAddress) external { + StoreSwitch.setStoreAddress(worldAddress); + + address bob = makeAddr("bob"); + address alice = makeAddr("alice"); + address mary = makeAddr("mary"); + address joe = makeAddr("joe"); + + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + vm.startBroadcast(deployerPrivateKey); + + Position.set({ player: bob, x: 1, y: -1 }); + Health.set({ player: bob, health: 5 }); + + Position.set({ player: alice, x: 3, y: 5 }); + Health.set({ player: alice, health: 5 }); + + Position.set({ player: mary, x: 3, y: 5 }); + Health.set({ player: mary, health: 0 }); + + Position.set({ player: joe, x: 100, y: 100 }); + + Terrain.set({ x: 3, y: 5, terrainType: TerrainType.Grassland }); + + vm.stopBroadcast(); + } +} diff --git a/test/mock-game-contracts/src/codegen/common.sol b/test/mock-game-contracts/src/codegen/common.sol new file mode 100644 index 0000000000..2c1249cfb8 --- /dev/null +++ b/test/mock-game-contracts/src/codegen/common.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +/* Autogenerated file. Do not edit manually. */ +enum TerrainType { + None, + Ocean, + Grassland, + Desert +} diff --git a/test/mock-game-contracts/src/codegen/index.sol b/test/mock-game-contracts/src/codegen/index.sol new file mode 100644 index 0000000000..3c8fe9368a --- /dev/null +++ b/test/mock-game-contracts/src/codegen/index.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +/* Autogenerated file. Do not edit manually. */ + +import { Position, PositionData } from "./tables/Position.sol"; +import { Health } from "./tables/Health.sol"; +import { Inventory } from "./tables/Inventory.sol"; +import { Score } from "./tables/Score.sol"; +import { Winner } from "./tables/Winner.sol"; +import { Terrain } from "./tables/Terrain.sol"; diff --git a/test/mock-game-contracts/src/codegen/tables/Health.sol b/test/mock-game-contracts/src/codegen/tables/Health.sol new file mode 100644 index 0000000000..f954023e77 --- /dev/null +++ b/test/mock-game-contracts/src/codegen/tables/Health.sol @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +/* Autogenerated file. Do not edit manually. */ + +// 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 { FieldLayout } from "@latticexyz/store/src/FieldLayout.sol"; +import { Schema } from "@latticexyz/store/src/Schema.sol"; +import { PackedCounter, PackedCounterLib } from "@latticexyz/store/src/PackedCounter.sol"; +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; + +library Health { + // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "", name: "Health", typeId: RESOURCE_TABLE });` + ResourceId constant _tableId = ResourceId.wrap(0x746200000000000000000000000000004865616c746800000000000000000000); + + FieldLayout constant _fieldLayout = + FieldLayout.wrap(0x0020010020000000000000000000000000000000000000000000000000000000); + + // Hex-encoded key schema of (address) + Schema constant _keySchema = Schema.wrap(0x0014010061000000000000000000000000000000000000000000000000000000); + // Hex-encoded value schema of (uint256) + Schema constant _valueSchema = Schema.wrap(0x002001001f000000000000000000000000000000000000000000000000000000); + + /** + * @notice Get the table's key field names. + * @return keyNames An array of strings with the names of key fields. + */ + function getKeyNames() internal pure returns (string[] memory keyNames) { + keyNames = new string[](1); + keyNames[0] = "player"; + } + + /** + * @notice Get the table's value field names. + * @return fieldNames An array of strings with the names of value fields. + */ + function getFieldNames() internal pure returns (string[] memory fieldNames) { + fieldNames = new string[](1); + fieldNames[0] = "health"; + } + + /** + * @notice Register the table with its config. + */ + function register() internal { + StoreSwitch.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Register the table with its config. + */ + function _register() internal { + StoreCore.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Get health. + */ + function getHealth(address player) internal view returns (uint256 health) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get health. + */ + function _getHealth(address player) internal view returns (uint256 health) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get health. + */ + function get(address player) internal view returns (uint256 health) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get health. + */ + function _get(address player) internal view returns (uint256 health) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Set health. + */ + function setHealth(address player, uint256 health) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((health)), _fieldLayout); + } + + /** + * @notice Set health. + */ + function _setHealth(address player, uint256 health) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((health)), _fieldLayout); + } + + /** + * @notice Set health. + */ + function set(address player, uint256 health) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((health)), _fieldLayout); + } + + /** + * @notice Set health. + */ + function _set(address player, uint256 health) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((health)), _fieldLayout); + } + + /** + * @notice Delete all data for given keys. + */ + function deleteRecord(address player) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreSwitch.deleteRecord(_tableId, _keyTuple); + } + + /** + * @notice Delete all data for given keys. + */ + function _deleteRecord(address player) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); + } + + /** + * @notice Tightly pack static (fixed length) data using this table's schema. + * @return The static data, encoded into a sequence of bytes. + */ + function encodeStatic(uint256 health) internal pure returns (bytes memory) { + return abi.encodePacked(health); + } + + /** + * @notice Encode all of a record's fields. + * @return The static (fixed length) data, encoded into a sequence of bytes. + * @return The lengths of the dynamic fields (packed into a single bytes32 value). + * @return The dynamic (variable length) data, encoded into a sequence of bytes. + */ + function encode(uint256 health) internal pure returns (bytes memory, PackedCounter, bytes memory) { + bytes memory _staticData = encodeStatic(health); + + PackedCounter _encodedLengths; + bytes memory _dynamicData; + + return (_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Encode keys as a bytes32 array using this table's field layout. + */ + function encodeKeyTuple(address player) internal pure returns (bytes32[] memory) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + return _keyTuple; + } +} diff --git a/test/mock-game-contracts/src/codegen/tables/Inventory.sol b/test/mock-game-contracts/src/codegen/tables/Inventory.sol new file mode 100644 index 0000000000..d2ebb1e7de --- /dev/null +++ b/test/mock-game-contracts/src/codegen/tables/Inventory.sol @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +/* Autogenerated file. Do not edit manually. */ + +// 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 { FieldLayout } from "@latticexyz/store/src/FieldLayout.sol"; +import { Schema } from "@latticexyz/store/src/Schema.sol"; +import { PackedCounter, PackedCounterLib } from "@latticexyz/store/src/PackedCounter.sol"; +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; + +library Inventory { + // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "", name: "Inventory", typeId: RESOURCE_TABLE });` + ResourceId constant _tableId = ResourceId.wrap(0x74620000000000000000000000000000496e76656e746f727900000000000000); + + FieldLayout constant _fieldLayout = + FieldLayout.wrap(0x0004010004000000000000000000000000000000000000000000000000000000); + + // Hex-encoded key schema of (address, uint8) + Schema constant _keySchema = Schema.wrap(0x0015020061000000000000000000000000000000000000000000000000000000); + // Hex-encoded value schema of (uint32) + Schema constant _valueSchema = Schema.wrap(0x0004010003000000000000000000000000000000000000000000000000000000); + + /** + * @notice Get the table's key field names. + * @return keyNames An array of strings with the names of key fields. + */ + function getKeyNames() internal pure returns (string[] memory keyNames) { + keyNames = new string[](2); + keyNames[0] = "player"; + keyNames[1] = "item"; + } + + /** + * @notice Get the table's value field names. + * @return fieldNames An array of strings with the names of value fields. + */ + function getFieldNames() internal pure returns (string[] memory fieldNames) { + fieldNames = new string[](1); + fieldNames[0] = "amount"; + } + + /** + * @notice Register the table with its config. + */ + function register() internal { + StoreSwitch.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Register the table with its config. + */ + function _register() internal { + StoreCore.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Get amount. + */ + function getAmount(address player, uint8 item) internal view returns (uint32 amount) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(item)); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint32(bytes4(_blob))); + } + + /** + * @notice Get amount. + */ + function _getAmount(address player, uint8 item) internal view returns (uint32 amount) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(item)); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint32(bytes4(_blob))); + } + + /** + * @notice Get amount. + */ + function get(address player, uint8 item) internal view returns (uint32 amount) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(item)); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint32(bytes4(_blob))); + } + + /** + * @notice Get amount. + */ + function _get(address player, uint8 item) internal view returns (uint32 amount) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(item)); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint32(bytes4(_blob))); + } + + /** + * @notice Set amount. + */ + function setAmount(address player, uint8 item, uint32 amount) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(item)); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((amount)), _fieldLayout); + } + + /** + * @notice Set amount. + */ + function _setAmount(address player, uint8 item, uint32 amount) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(item)); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((amount)), _fieldLayout); + } + + /** + * @notice Set amount. + */ + function set(address player, uint8 item, uint32 amount) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(item)); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((amount)), _fieldLayout); + } + + /** + * @notice Set amount. + */ + function _set(address player, uint8 item, uint32 amount) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(item)); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((amount)), _fieldLayout); + } + + /** + * @notice Delete all data for given keys. + */ + function deleteRecord(address player, uint8 item) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(item)); + + StoreSwitch.deleteRecord(_tableId, _keyTuple); + } + + /** + * @notice Delete all data for given keys. + */ + function _deleteRecord(address player, uint8 item) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(item)); + + StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); + } + + /** + * @notice Tightly pack static (fixed length) data using this table's schema. + * @return The static data, encoded into a sequence of bytes. + */ + function encodeStatic(uint32 amount) internal pure returns (bytes memory) { + return abi.encodePacked(amount); + } + + /** + * @notice Encode all of a record's fields. + * @return The static (fixed length) data, encoded into a sequence of bytes. + * @return The lengths of the dynamic fields (packed into a single bytes32 value). + * @return The dynamic (variable length) data, encoded into a sequence of bytes. + */ + function encode(uint32 amount) internal pure returns (bytes memory, PackedCounter, bytes memory) { + bytes memory _staticData = encodeStatic(amount); + + PackedCounter _encodedLengths; + bytes memory _dynamicData; + + return (_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Encode keys as a bytes32 array using this table's field layout. + */ + function encodeKeyTuple(address player, uint8 item) internal pure returns (bytes32[] memory) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(item)); + + return _keyTuple; + } +} diff --git a/test/mock-game-contracts/src/codegen/tables/Position.sol b/test/mock-game-contracts/src/codegen/tables/Position.sol new file mode 100644 index 0000000000..1c031eb763 --- /dev/null +++ b/test/mock-game-contracts/src/codegen/tables/Position.sol @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +/* Autogenerated file. Do not edit manually. */ + +// 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 { FieldLayout } from "@latticexyz/store/src/FieldLayout.sol"; +import { Schema } from "@latticexyz/store/src/Schema.sol"; +import { PackedCounter, PackedCounterLib } from "@latticexyz/store/src/PackedCounter.sol"; +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; + +struct PositionData { + int32 x; + int32 y; +} + +library Position { + // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "", name: "Position", typeId: RESOURCE_TABLE });` + ResourceId constant _tableId = ResourceId.wrap(0x74620000000000000000000000000000506f736974696f6e0000000000000000); + + FieldLayout constant _fieldLayout = + FieldLayout.wrap(0x0008020004040000000000000000000000000000000000000000000000000000); + + // Hex-encoded key schema of (address) + Schema constant _keySchema = Schema.wrap(0x0014010061000000000000000000000000000000000000000000000000000000); + // Hex-encoded value schema of (int32, int32) + Schema constant _valueSchema = Schema.wrap(0x0008020023230000000000000000000000000000000000000000000000000000); + + /** + * @notice Get the table's key field names. + * @return keyNames An array of strings with the names of key fields. + */ + function getKeyNames() internal pure returns (string[] memory keyNames) { + keyNames = new string[](1); + keyNames[0] = "player"; + } + + /** + * @notice Get the table's value field names. + * @return fieldNames An array of strings with the names of value fields. + */ + function getFieldNames() internal pure returns (string[] memory fieldNames) { + fieldNames = new string[](2); + fieldNames[0] = "x"; + fieldNames[1] = "y"; + } + + /** + * @notice Register the table with its config. + */ + function register() internal { + StoreSwitch.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Register the table with its config. + */ + function _register() internal { + StoreCore.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Get x. + */ + function getX(address player) internal view returns (int32 x) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (int32(uint32(bytes4(_blob)))); + } + + /** + * @notice Get x. + */ + function _getX(address player) internal view returns (int32 x) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (int32(uint32(bytes4(_blob)))); + } + + /** + * @notice Set x. + */ + function setX(address player, int32 x) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((x)), _fieldLayout); + } + + /** + * @notice Set x. + */ + function _setX(address player, int32 x) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((x)), _fieldLayout); + } + + /** + * @notice Get y. + */ + function getY(address player) internal view returns (int32 y) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 1, _fieldLayout); + return (int32(uint32(bytes4(_blob)))); + } + + /** + * @notice Get y. + */ + function _getY(address player) internal view returns (int32 y) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 1, _fieldLayout); + return (int32(uint32(bytes4(_blob)))); + } + + /** + * @notice Set y. + */ + function setY(address player, int32 y) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 1, abi.encodePacked((y)), _fieldLayout); + } + + /** + * @notice Set y. + */ + function _setY(address player, int32 y) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreCore.setStaticField(_tableId, _keyTuple, 1, abi.encodePacked((y)), _fieldLayout); + } + + /** + * @notice Get the full data. + */ + function get(address player) internal view returns (PositionData memory _table) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + (bytes memory _staticData, PackedCounter _encodedLengths, bytes memory _dynamicData) = StoreSwitch.getRecord( + _tableId, + _keyTuple, + _fieldLayout + ); + return decode(_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Get the full data. + */ + function _get(address player) internal view returns (PositionData memory _table) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + (bytes memory _staticData, PackedCounter _encodedLengths, bytes memory _dynamicData) = StoreCore.getRecord( + _tableId, + _keyTuple, + _fieldLayout + ); + return decode(_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Set the full data using individual values. + */ + function set(address player, int32 x, int32 y) internal { + bytes memory _staticData = encodeStatic(x, y); + + PackedCounter _encodedLengths; + bytes memory _dynamicData; + + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreSwitch.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Set the full data using individual values. + */ + function _set(address player, int32 x, int32 y) internal { + bytes memory _staticData = encodeStatic(x, y); + + PackedCounter _encodedLengths; + bytes memory _dynamicData; + + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreCore.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData, _fieldLayout); + } + + /** + * @notice Set the full data using the data struct. + */ + function set(address player, PositionData memory _table) internal { + bytes memory _staticData = encodeStatic(_table.x, _table.y); + + PackedCounter _encodedLengths; + bytes memory _dynamicData; + + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreSwitch.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Set the full data using the data struct. + */ + function _set(address player, PositionData memory _table) internal { + bytes memory _staticData = encodeStatic(_table.x, _table.y); + + PackedCounter _encodedLengths; + bytes memory _dynamicData; + + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreCore.setRecord(_tableId, _keyTuple, _staticData, _encodedLengths, _dynamicData, _fieldLayout); + } + + /** + * @notice Decode the tightly packed blob of static data using this table's field layout. + */ + function decodeStatic(bytes memory _blob) internal pure returns (int32 x, int32 y) { + x = (int32(uint32(Bytes.slice4(_blob, 0)))); + + y = (int32(uint32(Bytes.slice4(_blob, 4)))); + } + + /** + * @notice Decode the tightly packed blobs using this table's field layout. + * @param _staticData Tightly packed static fields. + * + * + */ + function decode( + bytes memory _staticData, + PackedCounter, + bytes memory + ) internal pure returns (PositionData memory _table) { + (_table.x, _table.y) = decodeStatic(_staticData); + } + + /** + * @notice Delete all data for given keys. + */ + function deleteRecord(address player) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreSwitch.deleteRecord(_tableId, _keyTuple); + } + + /** + * @notice Delete all data for given keys. + */ + function _deleteRecord(address player) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); + } + + /** + * @notice Tightly pack static (fixed length) data using this table's schema. + * @return The static data, encoded into a sequence of bytes. + */ + function encodeStatic(int32 x, int32 y) internal pure returns (bytes memory) { + return abi.encodePacked(x, y); + } + + /** + * @notice Encode all of a record's fields. + * @return The static (fixed length) data, encoded into a sequence of bytes. + * @return The lengths of the dynamic fields (packed into a single bytes32 value). + * @return The dynamic (variable length) data, encoded into a sequence of bytes. + */ + function encode(int32 x, int32 y) internal pure returns (bytes memory, PackedCounter, bytes memory) { + bytes memory _staticData = encodeStatic(x, y); + + PackedCounter _encodedLengths; + bytes memory _dynamicData; + + return (_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Encode keys as a bytes32 array using this table's field layout. + */ + function encodeKeyTuple(address player) internal pure returns (bytes32[] memory) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(uint160(player))); + + return _keyTuple; + } +} diff --git a/test/mock-game-contracts/src/codegen/tables/Score.sol b/test/mock-game-contracts/src/codegen/tables/Score.sol new file mode 100644 index 0000000000..e1b6c84a66 --- /dev/null +++ b/test/mock-game-contracts/src/codegen/tables/Score.sol @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +/* Autogenerated file. Do not edit manually. */ + +// 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 { FieldLayout } from "@latticexyz/store/src/FieldLayout.sol"; +import { Schema } from "@latticexyz/store/src/Schema.sol"; +import { PackedCounter, PackedCounterLib } from "@latticexyz/store/src/PackedCounter.sol"; +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; + +library Score { + // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "", name: "Score", typeId: RESOURCE_TABLE });` + ResourceId constant _tableId = ResourceId.wrap(0x7462000000000000000000000000000053636f72650000000000000000000000); + + FieldLayout constant _fieldLayout = + FieldLayout.wrap(0x0020010020000000000000000000000000000000000000000000000000000000); + + // Hex-encoded key schema of (address, uint256) + Schema constant _keySchema = Schema.wrap(0x00340200611f0000000000000000000000000000000000000000000000000000); + // Hex-encoded value schema of (uint256) + Schema constant _valueSchema = Schema.wrap(0x002001001f000000000000000000000000000000000000000000000000000000); + + /** + * @notice Get the table's key field names. + * @return keyNames An array of strings with the names of key fields. + */ + function getKeyNames() internal pure returns (string[] memory keyNames) { + keyNames = new string[](2); + keyNames[0] = "player"; + keyNames[1] = "game"; + } + + /** + * @notice Get the table's value field names. + * @return fieldNames An array of strings with the names of value fields. + */ + function getFieldNames() internal pure returns (string[] memory fieldNames) { + fieldNames = new string[](1); + fieldNames[0] = "score"; + } + + /** + * @notice Register the table with its config. + */ + function register() internal { + StoreSwitch.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Register the table with its config. + */ + function _register() internal { + StoreCore.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Get score. + */ + function getScore(address player, uint256 game) internal view returns (uint256 score) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(game)); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get score. + */ + function _getScore(address player, uint256 game) internal view returns (uint256 score) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(game)); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get score. + */ + function get(address player, uint256 game) internal view returns (uint256 score) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(game)); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Get score. + */ + function _get(address player, uint256 game) internal view returns (uint256 score) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(game)); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (uint256(bytes32(_blob))); + } + + /** + * @notice Set score. + */ + function setScore(address player, uint256 game, uint256 score) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(game)); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((score)), _fieldLayout); + } + + /** + * @notice Set score. + */ + function _setScore(address player, uint256 game, uint256 score) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(game)); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((score)), _fieldLayout); + } + + /** + * @notice Set score. + */ + function set(address player, uint256 game, uint256 score) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(game)); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((score)), _fieldLayout); + } + + /** + * @notice Set score. + */ + function _set(address player, uint256 game, uint256 score) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(game)); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((score)), _fieldLayout); + } + + /** + * @notice Delete all data for given keys. + */ + function deleteRecord(address player, uint256 game) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(game)); + + StoreSwitch.deleteRecord(_tableId, _keyTuple); + } + + /** + * @notice Delete all data for given keys. + */ + function _deleteRecord(address player, uint256 game) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(game)); + + StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); + } + + /** + * @notice Tightly pack static (fixed length) data using this table's schema. + * @return The static data, encoded into a sequence of bytes. + */ + function encodeStatic(uint256 score) internal pure returns (bytes memory) { + return abi.encodePacked(score); + } + + /** + * @notice Encode all of a record's fields. + * @return The static (fixed length) data, encoded into a sequence of bytes. + * @return The lengths of the dynamic fields (packed into a single bytes32 value). + * @return The dynamic (variable length) data, encoded into a sequence of bytes. + */ + function encode(uint256 score) internal pure returns (bytes memory, PackedCounter, bytes memory) { + bytes memory _staticData = encodeStatic(score); + + PackedCounter _encodedLengths; + bytes memory _dynamicData; + + return (_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Encode keys as a bytes32 array using this table's field layout. + */ + function encodeKeyTuple(address player, uint256 game) internal pure returns (bytes32[] memory) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(uint160(player))); + _keyTuple[1] = bytes32(uint256(game)); + + return _keyTuple; + } +} diff --git a/test/mock-game-contracts/src/codegen/tables/Terrain.sol b/test/mock-game-contracts/src/codegen/tables/Terrain.sol new file mode 100644 index 0000000000..d3bf87575f --- /dev/null +++ b/test/mock-game-contracts/src/codegen/tables/Terrain.sol @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +/* Autogenerated file. Do not edit manually. */ + +// 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 { FieldLayout } from "@latticexyz/store/src/FieldLayout.sol"; +import { Schema } from "@latticexyz/store/src/Schema.sol"; +import { PackedCounter, PackedCounterLib } from "@latticexyz/store/src/PackedCounter.sol"; +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; + +// Import user types +import { TerrainType } from "./../common.sol"; + +library Terrain { + // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "", name: "Terrain", typeId: RESOURCE_TABLE });` + ResourceId constant _tableId = ResourceId.wrap(0x746200000000000000000000000000005465727261696e000000000000000000); + + FieldLayout constant _fieldLayout = + FieldLayout.wrap(0x0001010001000000000000000000000000000000000000000000000000000000); + + // Hex-encoded key schema of (int32, int32) + Schema constant _keySchema = Schema.wrap(0x0008020023230000000000000000000000000000000000000000000000000000); + // Hex-encoded value schema of (uint8) + Schema constant _valueSchema = Schema.wrap(0x0001010000000000000000000000000000000000000000000000000000000000); + + /** + * @notice Get the table's key field names. + * @return keyNames An array of strings with the names of key fields. + */ + function getKeyNames() internal pure returns (string[] memory keyNames) { + keyNames = new string[](2); + keyNames[0] = "x"; + keyNames[1] = "y"; + } + + /** + * @notice Get the table's value field names. + * @return fieldNames An array of strings with the names of value fields. + */ + function getFieldNames() internal pure returns (string[] memory fieldNames) { + fieldNames = new string[](1); + fieldNames[0] = "terrainType"; + } + + /** + * @notice Register the table with its config. + */ + function register() internal { + StoreSwitch.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Register the table with its config. + */ + function _register() internal { + StoreCore.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Get terrainType. + */ + function getTerrainType(int32 x, int32 y) internal view returns (TerrainType terrainType) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(int256(x))); + _keyTuple[1] = bytes32(uint256(int256(y))); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return TerrainType(uint8(bytes1(_blob))); + } + + /** + * @notice Get terrainType. + */ + function _getTerrainType(int32 x, int32 y) internal view returns (TerrainType terrainType) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(int256(x))); + _keyTuple[1] = bytes32(uint256(int256(y))); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return TerrainType(uint8(bytes1(_blob))); + } + + /** + * @notice Get terrainType. + */ + function get(int32 x, int32 y) internal view returns (TerrainType terrainType) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(int256(x))); + _keyTuple[1] = bytes32(uint256(int256(y))); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return TerrainType(uint8(bytes1(_blob))); + } + + /** + * @notice Get terrainType. + */ + function _get(int32 x, int32 y) internal view returns (TerrainType terrainType) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(int256(x))); + _keyTuple[1] = bytes32(uint256(int256(y))); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return TerrainType(uint8(bytes1(_blob))); + } + + /** + * @notice Set terrainType. + */ + function setTerrainType(int32 x, int32 y, TerrainType terrainType) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(int256(x))); + _keyTuple[1] = bytes32(uint256(int256(y))); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked(uint8(terrainType)), _fieldLayout); + } + + /** + * @notice Set terrainType. + */ + function _setTerrainType(int32 x, int32 y, TerrainType terrainType) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(int256(x))); + _keyTuple[1] = bytes32(uint256(int256(y))); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked(uint8(terrainType)), _fieldLayout); + } + + /** + * @notice Set terrainType. + */ + function set(int32 x, int32 y, TerrainType terrainType) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(int256(x))); + _keyTuple[1] = bytes32(uint256(int256(y))); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked(uint8(terrainType)), _fieldLayout); + } + + /** + * @notice Set terrainType. + */ + function _set(int32 x, int32 y, TerrainType terrainType) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(int256(x))); + _keyTuple[1] = bytes32(uint256(int256(y))); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked(uint8(terrainType)), _fieldLayout); + } + + /** + * @notice Delete all data for given keys. + */ + function deleteRecord(int32 x, int32 y) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(int256(x))); + _keyTuple[1] = bytes32(uint256(int256(y))); + + StoreSwitch.deleteRecord(_tableId, _keyTuple); + } + + /** + * @notice Delete all data for given keys. + */ + function _deleteRecord(int32 x, int32 y) internal { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(int256(x))); + _keyTuple[1] = bytes32(uint256(int256(y))); + + StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); + } + + /** + * @notice Tightly pack static (fixed length) data using this table's schema. + * @return The static data, encoded into a sequence of bytes. + */ + function encodeStatic(TerrainType terrainType) internal pure returns (bytes memory) { + return abi.encodePacked(terrainType); + } + + /** + * @notice Encode all of a record's fields. + * @return The static (fixed length) data, encoded into a sequence of bytes. + * @return The lengths of the dynamic fields (packed into a single bytes32 value). + * @return The dynamic (variable length) data, encoded into a sequence of bytes. + */ + function encode(TerrainType terrainType) internal pure returns (bytes memory, PackedCounter, bytes memory) { + bytes memory _staticData = encodeStatic(terrainType); + + PackedCounter _encodedLengths; + bytes memory _dynamicData; + + return (_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Encode keys as a bytes32 array using this table's field layout. + */ + function encodeKeyTuple(int32 x, int32 y) internal pure returns (bytes32[] memory) { + bytes32[] memory _keyTuple = new bytes32[](2); + _keyTuple[0] = bytes32(uint256(int256(x))); + _keyTuple[1] = bytes32(uint256(int256(y))); + + return _keyTuple; + } +} diff --git a/test/mock-game-contracts/src/codegen/tables/Winner.sol b/test/mock-game-contracts/src/codegen/tables/Winner.sol new file mode 100644 index 0000000000..61e8222060 --- /dev/null +++ b/test/mock-game-contracts/src/codegen/tables/Winner.sol @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +/* Autogenerated file. Do not edit manually. */ + +// 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 { FieldLayout } from "@latticexyz/store/src/FieldLayout.sol"; +import { Schema } from "@latticexyz/store/src/Schema.sol"; +import { PackedCounter, PackedCounterLib } from "@latticexyz/store/src/PackedCounter.sol"; +import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; + +library Winner { + // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "", name: "Winner", typeId: RESOURCE_TABLE });` + ResourceId constant _tableId = ResourceId.wrap(0x7462000000000000000000000000000057696e6e657200000000000000000000); + + FieldLayout constant _fieldLayout = + FieldLayout.wrap(0x0014010014000000000000000000000000000000000000000000000000000000); + + // Hex-encoded key schema of (uint256) + Schema constant _keySchema = Schema.wrap(0x002001001f000000000000000000000000000000000000000000000000000000); + // Hex-encoded value schema of (address) + Schema constant _valueSchema = Schema.wrap(0x0014010061000000000000000000000000000000000000000000000000000000); + + /** + * @notice Get the table's key field names. + * @return keyNames An array of strings with the names of key fields. + */ + function getKeyNames() internal pure returns (string[] memory keyNames) { + keyNames = new string[](1); + keyNames[0] = "game"; + } + + /** + * @notice Get the table's value field names. + * @return fieldNames An array of strings with the names of value fields. + */ + function getFieldNames() internal pure returns (string[] memory fieldNames) { + fieldNames = new string[](1); + fieldNames[0] = "player"; + } + + /** + * @notice Register the table with its config. + */ + function register() internal { + StoreSwitch.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Register the table with its config. + */ + function _register() internal { + StoreCore.registerTable(_tableId, _fieldLayout, _keySchema, _valueSchema, getKeyNames(), getFieldNames()); + } + + /** + * @notice Get player. + */ + function getPlayer(uint256 game) internal view returns (address player) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(game)); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (address(bytes20(_blob))); + } + + /** + * @notice Get player. + */ + function _getPlayer(uint256 game) internal view returns (address player) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(game)); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (address(bytes20(_blob))); + } + + /** + * @notice Get player. + */ + function get(uint256 game) internal view returns (address player) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(game)); + + bytes32 _blob = StoreSwitch.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (address(bytes20(_blob))); + } + + /** + * @notice Get player. + */ + function _get(uint256 game) internal view returns (address player) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(game)); + + bytes32 _blob = StoreCore.getStaticField(_tableId, _keyTuple, 0, _fieldLayout); + return (address(bytes20(_blob))); + } + + /** + * @notice Set player. + */ + function setPlayer(uint256 game, address player) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(game)); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((player)), _fieldLayout); + } + + /** + * @notice Set player. + */ + function _setPlayer(uint256 game, address player) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(game)); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((player)), _fieldLayout); + } + + /** + * @notice Set player. + */ + function set(uint256 game, address player) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(game)); + + StoreSwitch.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((player)), _fieldLayout); + } + + /** + * @notice Set player. + */ + function _set(uint256 game, address player) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(game)); + + StoreCore.setStaticField(_tableId, _keyTuple, 0, abi.encodePacked((player)), _fieldLayout); + } + + /** + * @notice Delete all data for given keys. + */ + function deleteRecord(uint256 game) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(game)); + + StoreSwitch.deleteRecord(_tableId, _keyTuple); + } + + /** + * @notice Delete all data for given keys. + */ + function _deleteRecord(uint256 game) internal { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(game)); + + StoreCore.deleteRecord(_tableId, _keyTuple, _fieldLayout); + } + + /** + * @notice Tightly pack static (fixed length) data using this table's schema. + * @return The static data, encoded into a sequence of bytes. + */ + function encodeStatic(address player) internal pure returns (bytes memory) { + return abi.encodePacked(player); + } + + /** + * @notice Encode all of a record's fields. + * @return The static (fixed length) data, encoded into a sequence of bytes. + * @return The lengths of the dynamic fields (packed into a single bytes32 value). + * @return The dynamic (variable length) data, encoded into a sequence of bytes. + */ + function encode(address player) internal pure returns (bytes memory, PackedCounter, bytes memory) { + bytes memory _staticData = encodeStatic(player); + + PackedCounter _encodedLengths; + bytes memory _dynamicData; + + return (_staticData, _encodedLengths, _dynamicData); + } + + /** + * @notice Encode keys as a bytes32 array using this table's field layout. + */ + function encodeKeyTuple(uint256 game) internal pure returns (bytes32[] memory) { + bytes32[] memory _keyTuple = new bytes32[](1); + _keyTuple[0] = bytes32(uint256(game)); + + return _keyTuple; + } +} diff --git a/test/mock-game-contracts/src/codegen/world/IWorld.sol b/test/mock-game-contracts/src/codegen/world/IWorld.sol new file mode 100644 index 0000000000..4761e84790 --- /dev/null +++ b/test/mock-game-contracts/src/codegen/world/IWorld.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.8.24; + +/* Autogenerated file. Do not edit manually. */ + +import { IBaseWorld } from "@latticexyz/world/src/codegen/interfaces/IBaseWorld.sol"; + +/** + * @title IWorld + * @author MUD (https://mud.dev) by Lattice (https://lattice.xyz) + * @notice This interface integrates all systems and associated function selectors + * that are dynamically registered in the World during deployment. + * @dev This is an autogenerated file; do not edit manually. + */ +interface IWorld is IBaseWorld {} diff --git a/test/mock-game-contracts/tsconfig.json b/test/mock-game-contracts/tsconfig.json new file mode 100644 index 0000000000..270db8fdf6 --- /dev/null +++ b/test/mock-game-contracts/tsconfig.json @@ -0,0 +1,13 @@ +// Visit https://aka.ms/tsconfig.json for all config options +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "strict": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node" + } +}