2025-05-08 23:41:55 +07:00
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 ) )
} ,
)