Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP sky strife playtest #1571

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/snapshot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ jobs:
release-snapshot:
name: Publish snapshot release to npm
runs-on: ubuntu-latest
if: github.event_name != 'workflow_dispatch'
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/commands/trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { MUDError } from "@latticexyz/common/errors";
import { cast, getRpcUrl, getSrcDirectory } from "@latticexyz/common/foundry";
import { StoreConfig } from "@latticexyz/store";
import { resolveWorldConfig, WorldConfig } from "@latticexyz/world";
import IBaseWorldData from "@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json" assert { type: "json" };
import IBaseWorldAbi from "@latticexyz/world/out/IBaseWorld.sol/IBaseWorld.abi.json" assert { type: "json" };
import worldConfig from "@latticexyz/world/mud.config.js";
import { tableIdToHex } from "@latticexyz/common";
import { getChainId, getExistingContracts } from "../utils";
Expand Down Expand Up @@ -65,7 +65,7 @@ const commandModule: CommandModule<Options, Options> = {

// Create World contract instance from deployed address
const provider = new ethers.providers.StaticJsonRpcProvider(rpc);
const WorldContract = new ethers.Contract(worldAddress, IBaseWorldData.abi, provider);
const WorldContract = new ethers.Contract(worldAddress, IBaseWorldAbi, provider);

// TODO account for multiple namespaces (https://github.com/latticexyz/mud/issues/994)
const namespace = mudConfig.namespace;
Expand Down
8 changes: 4 additions & 4 deletions packages/store-indexer/src/postgres/createQueryAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import { getAddress } from "viem";
*/
export async function createQueryAdapter(database: PgDatabase<any>): Promise<QueryAdapter> {
const adapter: QueryAdapter = {
async findAll(chainId, address) {
async findAll({ chainId, address, tableIds }) {
const internalTables = buildInternalTables();
const tables = (await getTables(database)).filter(
(table) => address != null && getAddress(address) === getAddress(table.address)
);
const tables = (await getTables(database))
.filter((table) => address == null || getAddress(address) === getAddress(table.address))
.filter((table) => tableIds == null || tableIds.includes(table.tableId));

const tablesWithRecords = await Promise.all(
tables.map(async (table) => {
Expand Down
62 changes: 57 additions & 5 deletions packages/store-indexer/src/sqlite/createQueryAdapter.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { eq } from "drizzle-orm";
import { eq, inArray, and } from "drizzle-orm";
import { BaseSQLiteDatabase } from "drizzle-orm/sqlite-core";
import { createSqliteTable, chainState, getTables } from "@latticexyz/store-sync/sqlite";
import { QueryAdapter } from "@latticexyz/store-sync/trpc-indexer";
import { debug } from "../debug";
import { Hex, getAddress } from "viem";

/**
* Creates a storage adapter for the tRPC server/client to query data from SQLite.
Expand All @@ -12,12 +13,51 @@ import { debug } from "../debug";
*/
export async function createQueryAdapter(database: BaseSQLiteDatabase<"sync", any>): Promise<QueryAdapter> {
const adapter: QueryAdapter = {
async findAll(chainId, address) {
const tables = getTables(database).filter((table) => table.address === address);
async findAll({ chainId, address, tableIds, matchId }) {
const tables = getTables(database)
.filter((table) => address == null || getAddress(address) === getAddress(table.address))
.filter((table) => tableIds == null || tableIds.includes(table.tableId))
.filter((table) =>
// we don't need KeysWithValue tables
matchId != null ? table.namespace !== "keyswval" : true
);

const entities = ((): Hex[] => {
if (!address || !matchId) return [];
try {
const Position = createSqliteTable({
address,
namespace: "",
name: "Position",
keySchema: { key: "bytes32" },
valueSchema: {
x: "int32",
y: "int32",
z: "int32",
},
});
const positions = database.select().from(Position).where(eq(Position.z, matchId)).all();
return positions.map((pos) => pos.key);
} catch (error: unknown) {
return [];
}
})();

const tablesWithRecords = tables.map((table) => {
const sqliteTable = createSqliteTable(table);
const records = database.select().from(sqliteTable).where(eq(sqliteTable.__isDeleted, false)).all();
const records = database
.select()
.from(sqliteTable)
.where(
and(
eq(sqliteTable.__isDeleted, false),
entities.length &&
(table.name === "MoveDifficulty" || table.name === "TerrainType") /* || table.name === "ArmorModifier"*/
? inArray(sqliteTable.__key, entities)
: undefined
)
)
.all();
return {
...table,
records: records.map((record) => ({
Expand All @@ -35,7 +75,19 @@ export async function createQueryAdapter(database: BaseSQLiteDatabase<"sync", an
tables: tablesWithRecords,
};

debug("findAll", chainId, address, result);
const count = tablesWithRecords.reduce((sum, table) => sum + table.records.length, 0);

debug(
"findAll",
"chainId:",
chainId,
"address:",
address,
"tables:",
tablesWithRecords.length,
"records:",
count
);

return result;
},
Expand Down
6 changes: 6 additions & 0 deletions packages/store-sync/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ export type SyncOptions<TConfig extends StoreConfig = StoreConfig> = {
* Optional maximum block range, if your RPC limits the amount of blocks fetched at a time.
*/
maxBlockRange?: bigint;
/**
* Optional table IDs to filter indexer state and RPC state.
*/
tableIds?: Hex[];
/**
* Optional MUD tRPC indexer URL to fetch initial state from.
*/
Expand All @@ -110,6 +114,8 @@ export type SyncOptions<TConfig extends StoreConfig = StoreConfig> = {
blockNumber: bigint | null;
tables: TableWithRecords[];
};
/** Sky Strife-specific option to filter data by match ID */
matchId?: number;
};

export type SyncResult<TConfig extends StoreConfig = StoreConfig> = {
Expand Down
20 changes: 17 additions & 3 deletions packages/store-sync/src/createStoreSync.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ConfigToKeyPrimitives, ConfigToValuePrimitives, StoreConfig, storeEventsAbi } from "@latticexyz/store";
import { Hex, TransactionReceiptNotFoundError } from "viem";
import { SetRecordOperation, StorageAdapter, SyncOptions, SyncResult, TableWithRecords } from "./common";
import { BlockLogs, SetRecordOperation, StorageAdapter, SyncOptions, SyncResult, TableWithRecords } from "./common";
import { createBlockStream, blockRangeToLogs, groupLogsByBlockNumber } from "@latticexyz/block-logs-stream";
import {
filter,
Expand All @@ -19,6 +19,7 @@ import {
combineLatest,
scan,
identity,
Observable,
} from "rxjs";
import { BlockStorageOperations, blockLogsToStorage } from "./blockLogsToStorage";
import { debug as parentDebug } from "./debug";
Expand Down Expand Up @@ -48,8 +49,10 @@ export async function createStoreSync<TConfig extends StoreConfig = StoreConfig>
publicClient,
startBlock: initialStartBlock = 0n,
maxBlockRange,
tableIds,
initialState,
indexerUrl,
matchId,
}: CreateStoreSyncOptions<TConfig>): Promise<CreateStoreSyncResult<TConfig>> {
const initialState$ = defer(
async (): Promise<
Expand All @@ -74,7 +77,7 @@ export async function createStoreSync<TConfig extends StoreConfig = StoreConfig>

const indexer = createIndexerClient({ url: indexerUrl });
const chainId = publicClient.chain?.id ?? (await publicClient.getChainId());
const result = await indexer.findAll.query({ chainId, address });
const result = await indexer.findAll.query({ chainId, address, tableIds, matchId });

onProgress?.({
step: SyncStep.SNAPSHOT,
Expand Down Expand Up @@ -114,6 +117,13 @@ export async function createStoreSync<TConfig extends StoreConfig = StoreConfig>
(initialState): initialState is { blockNumber: bigint; tables: TableWithRecords[] } =>
initialState != null && initialState.blockNumber != null && initialState.tables.length > 0
),
// Initial state from indexer should already be filtered by table IDs, but we should
// still attempt to filter in case initialState was passed in as an argument or the
// indexer is being silly.
map(({ blockNumber, tables }) => ({
blockNumber,
tables: tables.filter((table) => tableIds != null && tableIds.includes(table.tableId)),
})),
concatMap(async ({ blockNumber, tables }) => {
debug("hydrating from initial state to block", blockNumber);

Expand Down Expand Up @@ -179,7 +189,7 @@ export async function createStoreSync<TConfig extends StoreConfig = StoreConfig>

let startBlock: bigint | null = null;
let endBlock: bigint | null = null;
const blockLogs$ = combineLatest([startBlock$, latestBlockNumber$]).pipe(
const blockLogs$: Observable<BlockLogs> = combineLatest([startBlock$, latestBlockNumber$]).pipe(
map(([startBlock, endBlock]) => ({ startBlock, endBlock })),
tap((range) => {
startBlock = range.startBlock;
Expand All @@ -192,6 +202,10 @@ export async function createStoreSync<TConfig extends StoreConfig = StoreConfig>
maxBlockRange,
}),
mergeMap(({ toBlock, logs }) => from(groupLogsByBlockNumber(logs, toBlock))),
map(({ blockNumber, logs }) => ({
blockNumber,
logs: logs.filter((log) => tableIds != null && tableIds.includes(log.args.table)),
})),
share()
);

Expand Down
2 changes: 2 additions & 0 deletions packages/store-sync/src/recs/syncToRecs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export async function syncToRecs<TConfig extends StoreConfig = StoreConfig>({
initialState,
indexerUrl,
startSync = true,
matchId,
}: SyncToRecsOptions<TConfig>): Promise<SyncToRecsResult<TConfig>> {
const { storageAdapter, components } = recsStorage({ world, config });

Expand All @@ -39,6 +40,7 @@ export async function syncToRecs<TConfig extends StoreConfig = StoreConfig>({
maxBlockRange,
indexerUrl,
initialState,
matchId,
onProgress: ({ step, percentage, latestBlockNumber, lastBlockNumberProcessed, message }) => {
if (getComponentValue(components.SyncProgress, singletonEntity)?.step !== SyncStep.LIVE) {
setComponent(components.SyncProgress, singletonEntity, {
Expand Down
5 changes: 1 addition & 4 deletions packages/store-sync/src/trpc-indexer/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import { Hex } from "viem";
import { TableWithRecords } from "../common";

export type QueryAdapter = {
findAll: (
chainId: number,
address?: Hex
) => Promise<{
findAll: (opts: { chainId: number; address?: Hex; tableIds?: Hex[]; matchId?: number }) => Promise<{
blockNumber: bigint | null;
tables: TableWithRecords[];
}>;
Expand Down
8 changes: 4 additions & 4 deletions packages/store-sync/src/trpc-indexer/createAppRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ export function createAppRouter() {
z.object({
chainId: z.number(),
address: z.string().refine(isHex).optional(),
tableIds: z.array(z.string().refine(isHex)).optional(),
matchId: z.number().optional(),
})
)
.query(async (opts): ReturnType<QueryAdapter["findAll"]> => {
const { queryAdapter } = opts.ctx;
const { chainId, address } = opts.input;
return queryAdapter.findAll(chainId, address);
.query(async ({ ctx, input }): ReturnType<QueryAdapter["findAll"]> => {
return ctx.queryAdapter.findAll(input);
}),
});
}
Expand Down
Loading