GoonCord/src/lib/api/assets.ts

80 lines
2.8 KiB
TypeScript
Raw Normal View History

import { after } from "@lib/api/patcher";
import { getMetroCache, indexAssetName } from "@metro/caches";
2024-05-20 15:36:33 +08:00
import { getImportingModuleId, requireModule } from "@metro/modules";
2022-10-22 23:26:06 +01:00
2024-06-02 02:32:01 +08:00
// TODO: Deprecate this map, make another that maps to an array of assets (Asset[]) instead
/**
* Pitfall: Multiple assets may have the same name, this is fine if we require the asset only for display,\
* but not when used to get the registered id/index. In some condition, this would break some plugins like HideGiftButton that gets id by name for patching.\
2024-06-02 02:32:01 +08:00
*/
export const assetsMap: Record<string, Asset> = new Proxy<any>({}, {
2024-06-02 02:32:01 +08:00
get(cache, p) {
if (typeof p !== "string") return undefined;
2024-06-02 02:32:01 +08:00
if (cache[p]) return cache[p];
2024-06-02 02:32:01 +08:00
const moduleIds = getMetroCache().assetsIndex[p];
if (moduleIds == null) return undefined;
2024-06-02 02:32:01 +08:00
for (const id in moduleIds) {
const assetIndex = requireModule(Number(id));
if (typeof assetIndex !== "number") continue;
const assetDefinition = assetsModule.getAssetByID(assetIndex);
if (!assetDefinition) continue;
2024-06-02 02:32:01 +08:00
assetDefinition.index ??= assetDefinition.id ??= assetIndex;
assetDefinition.moduleId ??= id;
2024-06-02 02:32:01 +08:00
// ??= is intended, we only assign to the first asset registered
// Though, VD seems to assign the last registered, but doing that breaks HideGiftButton so idk
// https://github.com/vendetta-mod/Vendetta/blob/rewrite/src/ui/assets.ts
cache[p] ??= assetDefinition;
}
return cache[p];
},
2024-06-02 02:32:01 +08:00
ownKeys(cache) {
const keys = [] as Array<string>;
for (const key in getMetroCache().assetsIndex) {
cache[key] = this.get!(cache, key, {});
if (cache[key]) keys.push(key);
}
return keys;
},
});
2022-10-22 23:26:06 +01:00
2024-02-23 15:11:35 +08:00
export interface Asset {
/** @deprecated */
2024-02-23 15:11:35 +08:00
id: number;
index: number;
name: string;
2024-05-10 02:15:32 +08:00
moduleId: number;
}
interface AssetModule {
registerAsset(assetDefinition: any): number;
getAssetByID(id: number): any;
2024-02-23 15:11:35 +08:00
}
2024-05-10 02:15:32 +08:00
let assetsModule: AssetModule;
2024-03-11 15:04:11 +08:00
/**
* @internal
*/
2024-05-10 02:15:32 +08:00
export function patchAssets(module: AssetModule) {
if (assetsModule) return;
assetsModule = module;
const unpatch = after("registerAsset", assetsModule, ([asset]: Asset[]) => {
const moduleId = getImportingModuleId();
if (moduleId !== -1) indexAssetName(asset.name, moduleId);
});
2022-10-22 23:26:06 +01:00
return unpatch;
2022-10-22 23:26:06 +01:00
}
export const findAsset = (filter: (a: any) => void): Asset | null | undefined => Object.values(assetsMap).find(filter);
export const requireAssetByName = (name: string): Asset => assetsMap[name];
export const requireAssetByIndex = (id: number): Asset => assetsModule.getAssetByID(id);
export const requireAssetIndex = (name: string) => assetsMap[name]?.index;