83 lines
3 KiB
TypeScript
83 lines
3 KiB
TypeScript
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))
|
|
},
|
|
)
|