chore(lib/assets): refactor
This commit is contained in:
parent
5de00474d4
commit
5587ede6ba
6 changed files with 101 additions and 86 deletions
|
|
@ -8,6 +8,9 @@
|
|||
},
|
||||
"./preinit": {
|
||||
"default": "./src/preinit.ts"
|
||||
},
|
||||
"./types": {
|
||||
"types": "./src/types.ts"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { Metro } from '@revenge-mod/modules/types'
|
||||
import type { Asset, AssetId } from '.'
|
||||
import type { Asset, AssetId } from './types'
|
||||
|
||||
export const _assets = new Map<string, [first: Asset, all: Record<Asset['type'], Asset>]>()
|
||||
export const _overrides = new Map<string, Asset>()
|
||||
|
|
|
|||
|
|
@ -1,19 +1,11 @@
|
|||
import { ReactNative } from '@revenge-mod/react'
|
||||
|
||||
import { _assets, _metas, _overrides } from './_internal'
|
||||
import { AssetRegistry } from './patches'
|
||||
import { AssetRegistry } from './preinit'
|
||||
|
||||
import type { ReactNative as RN } from '@revenge-mod/react/types'
|
||||
import type { Asset, AssetId, RegisterableAsset } from './types'
|
||||
|
||||
export type Asset = ReactNativeAsset | RevengeAsset
|
||||
export type AssetId = number
|
||||
|
||||
export type ReactNativeAsset = RN.AssetsRegistry.PackagerAsset
|
||||
export interface RevengeAsset extends Pick<ReactNativeAsset, 'name' | 'width' | 'height' | 'type'> {
|
||||
uri: string
|
||||
}
|
||||
|
||||
export type RegisterableAsset = Omit<RevengeAsset, 'id'>
|
||||
export * from './preinit'
|
||||
|
||||
// iOS cannot display SVGs
|
||||
let _preferredType: Asset['type'] = ReactNative.Platform.OS === 'ios' ? 'png' : 'svg'
|
||||
|
|
|
|||
|
|
@ -1,73 +0,0 @@
|
|||
import { _mInitingId, _mUninited } from '@revenge-mod/modules/_/metro'
|
||||
import { waitForModules } from '@revenge-mod/modules/finders'
|
||||
import { byName, byProps } from '@revenge-mod/modules/finders/filters'
|
||||
import { getModuleDependencies } from '@revenge-mod/modules/metro'
|
||||
|
||||
import { _assets, _metas, _overrides } from './_internal'
|
||||
|
||||
import type { ReactNative } from '@revenge-mod/react/types'
|
||||
import type { Asset, ReactNativeAsset } from '.'
|
||||
|
||||
export let AssetRegistry: ReactNative.AssetsRegistry
|
||||
export let AssetRegistryModuleId: number
|
||||
|
||||
// Tracking/caching assets
|
||||
const unsubForAssetRegistry = waitForModules(byProps('registerAsset'), (arId, exports) => {
|
||||
// We want to do caching only for the re-exported asset-registry
|
||||
if (!getModuleDependencies(arId)!.length) {
|
||||
AssetRegistry = exports as ReactNative.AssetsRegistry
|
||||
|
||||
const orig = exports.registerAsset
|
||||
exports.registerAsset = function registerAsset(asset: Asset) {
|
||||
const { name, type } = asset
|
||||
|
||||
// In-memory cache
|
||||
if (!_assets.has(name)) _assets.set(name, [asset, {}])
|
||||
const reg = _assets.get(name)!
|
||||
reg[1][type] = asset
|
||||
|
||||
const result = orig(asset)
|
||||
_metas.set(asset, [result, _mInitingId])
|
||||
return result
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
unsubForAssetRegistry()
|
||||
AssetRegistryModuleId = arId
|
||||
|
||||
// TODO(assets/patches): conditionally run this if cache does not exist
|
||||
// More fragile way, but more performant:
|
||||
// There is exactly one asset before the reexported asset registry, thanks Discord!
|
||||
const firstAssetModuleId = arId - 1
|
||||
for (const id of _mUninited) {
|
||||
if (id < firstAssetModuleId) continue
|
||||
|
||||
const deps = getModuleDependencies(id)!
|
||||
if (deps.length === 1 && deps[0] === arId) __r(id)
|
||||
}
|
||||
})
|
||||
|
||||
// Asset overrides
|
||||
const unsubForResolveAssetSource = waitForModules(
|
||||
byName<{
|
||||
addCustomSourceTransformer: (transformer: (arg: { asset: Asset }) => ReactNativeAsset) => void
|
||||
}>('resolveAssetSource'),
|
||||
(_, resolveAssetSource) => {
|
||||
unsubForResolveAssetSource()
|
||||
|
||||
// Custom assets
|
||||
// Why do we need to do this? Because RN/Dicord (unsure which) will attempt to resolve the asset via its path, which we don't provide via custom assets.
|
||||
// This will result in a crash, because it tries to read the path and run checks on it, but the path is undefined.
|
||||
// @ts-expect-error
|
||||
resolveAssetSource.addCustomSourceTransformer(({ asset }) => {
|
||||
// @ts-expect-error
|
||||
if (!asset.__packager_asset) return asset
|
||||
})
|
||||
|
||||
// Asset overrides
|
||||
// @ts-expect-error
|
||||
resolveAssetSource.addCustomSourceTransformer(({ asset }) => _overrides.get(asset.name))
|
||||
},
|
||||
)
|
||||
|
|
@ -1 +1,83 @@
|
|||
import './patches'
|
||||
import { _mInitingId, _mUninited } from '@revenge-mod/modules/_/metro'
|
||||
import { waitForModules } from '@revenge-mod/modules/finders'
|
||||
import { byName, byProps } from '@revenge-mod/modules/finders/filters'
|
||||
import { getModuleDependencies } from '@revenge-mod/modules/metro'
|
||||
|
||||
import { _assets, _metas, _overrides } from './_internal'
|
||||
|
||||
import type { ReactNative } from '@revenge-mod/react/types'
|
||||
import type { Asset, ReactNativeAsset } from './types'
|
||||
|
||||
export let AssetRegistry: ReactNative.AssetsRegistry
|
||||
export let AssetRegistryModuleId: number
|
||||
|
||||
// Tracking/caching assets
|
||||
const unsubAR = waitForModules(byProps<ReactNative.AssetsRegistry>('registerAsset'), (id, exports) => {
|
||||
AssetRegistryModuleId = id
|
||||
AssetRegistry = exports as ReactNative.AssetsRegistry
|
||||
|
||||
// There are two matching exports. One is the original, and one is a re-export.
|
||||
// The original asset-registry is simply required by the re-exported one with no changes.
|
||||
|
||||
// This is the re-exported registry, because it has dependencies.
|
||||
// We can begin the caching process here, asset registrar modules have the reexported registry as a dependency.
|
||||
if (getModuleDependencies(id)!.length) {
|
||||
unsubAR()
|
||||
|
||||
// TODO(assets/patches): conditionally run this if cache does not exist
|
||||
// More fragile way, but also more performant:
|
||||
// There is exactly one asset before the reexported asset registry :/
|
||||
const firstAssetModuleId = id - 1
|
||||
for (const mId of _mUninited) {
|
||||
if (mId < firstAssetModuleId) continue
|
||||
|
||||
const deps = getModuleDependencies(mId)!
|
||||
if (deps.length === 1 && deps[0] === id) __r(mId)
|
||||
}
|
||||
|
||||
// We already patched the original asset registry, so we don't need to patch again.
|
||||
return
|
||||
}
|
||||
|
||||
const orig = exports.registerAsset
|
||||
exports.registerAsset = (asset: Asset) => {
|
||||
const result = orig(asset as ReactNativeAsset)
|
||||
|
||||
const { name, type } = asset
|
||||
|
||||
let reg = _assets.get(name)
|
||||
if (!reg) {
|
||||
reg = [asset, {}]
|
||||
_assets.set(name, reg)
|
||||
}
|
||||
|
||||
// In-memory cache
|
||||
reg[1][type] = asset
|
||||
_metas.set(asset, [result, _mInitingId])
|
||||
|
||||
return result
|
||||
}
|
||||
})
|
||||
|
||||
// Asset overrides
|
||||
const unsubRAS = waitForModules(
|
||||
byName<{
|
||||
addCustomSourceTransformer: (transformer: (arg: { asset: Asset }) => ReactNativeAsset) => void
|
||||
}>('resolveAssetSource'),
|
||||
(_, rAS) => {
|
||||
unsubRAS()
|
||||
|
||||
// Custom assets
|
||||
// Why do we need to do this? Because RN/Dicord (unsure which) will attempt to resolve the asset via its path, which we don't provide via custom assets.
|
||||
// This will result in a crash, because it tries to read the path and run checks on it, but the path is undefined.
|
||||
// @ts-expect-error
|
||||
rAS.addCustomSourceTransformer(({ asset }) => {
|
||||
// @ts-expect-error
|
||||
if (!asset.__packager_asset) return asset
|
||||
})
|
||||
|
||||
// Asset overrides
|
||||
// @ts-expect-error
|
||||
rAS.addCustomSourceTransformer(({ asset }) => _overrides.get(asset.name))
|
||||
},
|
||||
)
|
||||
|
|
|
|||
11
lib/assets/src/types.ts
Normal file
11
lib/assets/src/types.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import type { ReactNative } from '@revenge-mod/react/types'
|
||||
|
||||
export type Asset = ReactNativeAsset | RevengeAsset
|
||||
export type AssetId = number
|
||||
|
||||
export type ReactNativeAsset = ReactNative.AssetsRegistry.PackagerAsset
|
||||
export interface RevengeAsset extends Pick<ReactNativeAsset, 'name' | 'width' | 'height' | 'type'> {
|
||||
uri: string
|
||||
}
|
||||
|
||||
export type RegisterableAsset = Omit<RevengeAsset, 'id'>
|
||||
Loading…
Add table
Reference in a new issue