Refactor database bootstrap: enhance primary key constraint handling for LeaderboardChannelMeta table to ensure correct schema migration

This commit is contained in:
Alexa
2026-06-06 20:40:30 +03:00
parent eb2fb0e1f1
commit 4d370bfcb9
2 changed files with 55 additions and 10 deletions
+40 -9
View File
@@ -1071,23 +1071,54 @@ internal static class DevMenuProbe
_frame++; _frame++;
if (_frame < 120) return; // ~2s — let MelonLoader/game boot if (_frame < 120) return; // ~2s — let MelonLoader/game boot
if ((_frame % 60) != 0) return; // then check ~once per second if ((_frame % 60) != 0) return; // then check ~once per second
// Wait until the watch's HomeScreenFlow is actually instantiated // Only fire once a REAL, in-scene HomeScreenFlow exists with its
// (only happens once you're in-game with the watch up), so the // UIBase wired (it gets assigned when the watch StackedUI initialises
// devMenuPanel/devButtonPrefab fields are meaningful. Give up and // in the dorm). The earlier version fired during boot on the loaded
// dump whatever exists after ~60s so we still get a report. // PREFAB (Resources.FindObjectsOfTypeAll returns prefabs/inactive,
// whose runtime UIBase is null) and, being one-shot, captured nothing
// and never retried. NO timeout now — we wait until the watch is up.
var homeType = Mod.ResolveType("AGUI.StackedUI.HomeScreenFlow") ?? Mod.ResolveType("HomeScreenFlow"); var homeType = Mod.ResolveType("AGUI.StackedUI.HomeScreenFlow") ?? Mod.ResolveType("HomeScreenFlow");
var homeLive = homeType != null && FindOne(homeType) != null; var home = homeType != null ? FindLiveHome(homeType) : null;
if (!homeLive && _frame < 3600) return; if (home == null)
{
if ((_frame % 600) == 0)
Mod.Log.Msg("[devmenu-probe] waiting for an in-scene HomeScreenFlow — enter your dorm / open the watch…");
return;
}
_done = true; _done = true;
try { Run(); } try { Run(homeType!, home); }
catch (Exception ex) { Mod.Log.Warning($"[devmenu-probe] failed: {ex}"); } catch (Exception ex) { Mod.Log.Warning($"[devmenu-probe] failed: {ex}"); }
} }
private static void Run() // The live HomeScreenFlow (UIBase wired), skipping the prefab/inactive
// copies FindObjectsOfTypeAll also returns.
private static object? FindLiveHome(Type homeType)
{
try
{
var il2 = ToIl2CppType(homeType);
if (il2 is null) return null;
var resources = Mod.ResolveType("UnityEngine.Resources");
var all = OneArgMethod(resources, "FindObjectsOfTypeAll", il2)?.Invoke(null, new[] { il2 });
int n = ArrLen(all);
for (int i = 0; i < n; i++)
{
var o = ArrItem(all, i);
if (o is null) continue;
if (GetMemberValue(homeType, o, "UIBase", "get_UIBase") != null) return o;
}
}
catch { }
return null;
}
private static void Run(Type homeType, object homeInst)
{ {
Mod.Log.Msg("=== [devmenu-probe] runtime dev-UI state ==="); Mod.Log.Msg("=== [devmenu-probe] runtime dev-UI state ===");
ProbeType("RecRoom.Core.WatchUI", "WatchUI", DumpWatchUi); ProbeType("RecRoom.Core.WatchUI", "WatchUI", DumpWatchUi);
ProbeType("AGUI.StackedUI.HomeScreenFlow", "HomeScreenFlow", DumpHomeScreen); Mod.Log.Msg($"[devmenu-probe] HomeScreenFlow: type={homeType.FullName}, liveInstance=FOUND (UIBase wired)");
try { DumpHomeScreen(homeType, homeInst); }
catch (Exception ex) { Mod.Log.Warning($"[devmenu-probe] HomeScreenFlow dump failed: {ex.Message}"); }
ProbeType("RecRoom.Debugging.DebugConsole", "DebugConsole", DumpDebugConsole); ProbeType("RecRoom.Debugging.DebugConsole", "DebugConsole", DumpDebugConsole);
Mod.Log.Msg("=== [devmenu-probe] done ==="); Mod.Log.Msg("=== [devmenu-probe] done ===");
} }
+15 -1
View File
@@ -337,7 +337,22 @@ public static class DatabaseBootstrap
DO $$ DO $$
DECLARE DECLARE
pk_cols text[]; pk_cols text[];
pk record;
BEGIN BEGIN
FOR pk IN
SELECT c.conname, array_agg(a.attname ORDER BY x.ordinality) AS cols
FROM pg_constraint c
JOIN unnest(c.conkey) WITH ORDINALITY AS x(attnum, ordinality) ON true
JOIN pg_attribute a ON a.attrelid = c.conrelid AND a.attnum = x.attnum
WHERE c.conrelid = '"LeaderboardChannelMeta"'::regclass
AND c.contype = 'p'
GROUP BY c.conname
LOOP
IF pk.cols IS DISTINCT FROM ARRAY['RoomId', 'Channel'] THEN
EXECUTE format('ALTER TABLE %I DROP CONSTRAINT %I', 'LeaderboardChannelMeta', pk.conname);
END IF;
END LOOP;
SELECT array_agg(a.attname ORDER BY x.ordinality) SELECT array_agg(a.attname ORDER BY x.ordinality)
INTO pk_cols INTO pk_cols
FROM pg_constraint c FROM pg_constraint c
@@ -347,7 +362,6 @@ public static class DatabaseBootstrap
AND c.contype = 'p'; AND c.contype = 'p';
IF pk_cols IS DISTINCT FROM ARRAY['RoomId', 'Channel'] THEN IF pk_cols IS DISTINCT FROM ARRAY['RoomId', 'Channel'] THEN
ALTER TABLE "LeaderboardChannelMeta" DROP CONSTRAINT IF EXISTS "PK_LeaderboardChannelMeta";
ALTER TABLE "LeaderboardChannelMeta" ALTER TABLE "LeaderboardChannelMeta"
ADD CONSTRAINT "PK_LeaderboardChannelMeta" PRIMARY KEY ("RoomId", "Channel"); ADD CONSTRAINT "PK_LeaderboardChannelMeta" PRIMARY KEY ("RoomId", "Channel");
END IF; END IF;