Fix BetterTimestamps/RoleColorEverywhere: RowManager lookup raced Metro's own module init
This commit is contained in:
parent
15ab318dcb
commit
51e34bbdb5
2 changed files with 66 additions and 35 deletions
|
|
@ -1,39 +1,53 @@
|
|||
import { findByName } from "@vendetta/metro";
|
||||
import { moment } from "@vendetta/metro/common";
|
||||
import { after, before } from "@vendetta/patcher";
|
||||
import { storage } from "@vendetta/plugin";
|
||||
import { waitFor } from "@shared/lib/waitFor";
|
||||
import { rawFindByName } from "@shared/lib/rawFind";
|
||||
import renderTimestamp from "../lib/renderTimestamp";
|
||||
|
||||
const RowManager = findByName("RowManager", false);
|
||||
|
||||
// RowManager used to be looked up eagerly at module-import time with the cached findByName - a
|
||||
// plugin's top-level code runs as soon as Discord requires its bundle, which can be before Discord's
|
||||
// own code has required RowManager itself, and Revenge's findByName permanently caches a negative
|
||||
// result. Confirmed live via Key Inspector's Eval console: a raw, uncached scan found
|
||||
// RowManager.prototype.generate present and correct once the module had actually initialized - the
|
||||
// class itself was never the problem, just the timing of a one-shot lookup racing it.
|
||||
export default function patchRowManager(): () => void {
|
||||
if (!RowManager?.prototype?.generate) return () => {};
|
||||
|
||||
const patches: (() => void)[] = [];
|
||||
|
||||
patches.push(before("generate", RowManager.prototype, ([row]: any[]) => {
|
||||
try {
|
||||
if (row.rowType === 1) {
|
||||
if (storage.separateMessages) row.isFirst = true;
|
||||
row.message.__customTimestamp = renderTimestamp(row.message.timestamp);
|
||||
} else if (row.rowType === "day") {
|
||||
row.text = renderTimestamp(moment(row.text, "LL"));
|
||||
}
|
||||
} catch {
|
||||
// Leave this row's timestamp untouched.
|
||||
}
|
||||
}));
|
||||
const handle = waitFor(
|
||||
() => {
|
||||
const RowManager = rawFindByName<any>("RowManager");
|
||||
return RowManager?.prototype?.generate ? RowManager : undefined;
|
||||
},
|
||||
(RowManager) => {
|
||||
patches.push(before("generate", RowManager.prototype, ([row]: any[]) => {
|
||||
try {
|
||||
if (row.rowType === 1) {
|
||||
if (storage.separateMessages) row.isFirst = true;
|
||||
row.message.__customTimestamp = renderTimestamp(row.message.timestamp);
|
||||
} else if (row.rowType === "day") {
|
||||
row.text = renderTimestamp(moment(row.text, "LL"));
|
||||
}
|
||||
} catch {
|
||||
// Leave this row's timestamp untouched.
|
||||
}
|
||||
}));
|
||||
|
||||
patches.push(after("generate", RowManager.prototype, ([row]: any[], result: any) => {
|
||||
try {
|
||||
if (row.rowType !== 1) return;
|
||||
if (row.message?.__customTimestamp && result?.message?.state === "SENT" && result.message.timestamp) {
|
||||
result.message.timestamp = row.message.__customTimestamp;
|
||||
}
|
||||
} catch {
|
||||
// Leave the default timestamp.
|
||||
patches.push(after("generate", RowManager.prototype, ([row]: any[], result: any) => {
|
||||
try {
|
||||
if (row.rowType !== 1) return;
|
||||
if (row.message?.__customTimestamp && result?.message?.state === "SENT" && result.message.timestamp) {
|
||||
result.message.timestamp = row.message.__customTimestamp;
|
||||
}
|
||||
} catch {
|
||||
// Leave the default timestamp.
|
||||
}
|
||||
}));
|
||||
}
|
||||
}));
|
||||
);
|
||||
|
||||
return () => patches.forEach((p) => p());
|
||||
return () => {
|
||||
handle.cancel();
|
||||
patches.forEach((p) => p());
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { findByName, findByStoreName } from "@vendetta/metro";
|
||||
import { findByStoreName } from "@vendetta/metro";
|
||||
import { ReactNative } from "@vendetta/metro/common";
|
||||
import { after, before } from "@vendetta/patcher";
|
||||
import { storage } from "@vendetta/plugin";
|
||||
import { waitFor } from "@shared/lib/waitFor";
|
||||
import { rawFindByName } from "@shared/lib/rawFind";
|
||||
import { defaultTextColor, interpolateColor } from "../lib/color";
|
||||
|
||||
const GuildMemberStore = findByStoreName("GuildMemberStore");
|
||||
const ChannelStore = findByStoreName("ChannelStore");
|
||||
const RowManager = findByName("RowManager", false);
|
||||
|
||||
function patchComponents(component: any, funcs: any[], args: any[], tree?: any[]): any {
|
||||
if (!component) return component;
|
||||
|
|
@ -118,11 +119,27 @@ export default function patchRows(): () => void {
|
|||
});
|
||||
}
|
||||
|
||||
if (RowManager?.prototype?.generate) {
|
||||
return after("generate", RowManager.prototype, (_: any, row: any) => {
|
||||
try { handleRow(row); } catch { /* skip this row */ }
|
||||
});
|
||||
}
|
||||
// RowManager used to be looked up eagerly at module-import time with the cached findByName - a
|
||||
// plugin's top-level code can run before Discord's own code has required RowManager itself, and
|
||||
// Revenge's findByName permanently caches a negative result. Confirmed live via Key Inspector's
|
||||
// Eval console: a raw, uncached scan found RowManager.prototype.generate present once the module
|
||||
// had actually initialized - waitFor + a raw lookup retries until that happens instead of giving
|
||||
// up on the first (possibly premature) miss.
|
||||
const patches: (() => void)[] = [];
|
||||
const handle = waitFor(
|
||||
() => {
|
||||
const RowManager = rawFindByName<any>("RowManager");
|
||||
return RowManager?.prototype?.generate ? RowManager : undefined;
|
||||
},
|
||||
(RowManager) => {
|
||||
patches.push(after("generate", RowManager.prototype, (_: any, row: any) => {
|
||||
try { handleRow(row); } catch { /* skip this row */ }
|
||||
}));
|
||||
}
|
||||
);
|
||||
|
||||
return () => {};
|
||||
return () => {
|
||||
handle.cancel();
|
||||
patches.forEach((p) => p());
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue