You are viewing a potentially older version of this package. View all versions.
bdub-UnlockChecklist-0.1.0 icon

UnlockChecklist

Tag locked skills, skins and survivors from the character-select loadout panel, then read the unlock requirements back as a checklist in game. Client-side and read-only.

By bdub
Date uploaded 18 hours ago
Version 0.1.0
Download link bdub-UnlockChecklist-0.1.0.zip
Downloads 21
Dependency string bdub-UnlockChecklist-0.1.0

This mod requires the following mods to function

bbepis-BepInExPack-5.4.2122 icon
bbepis-BepInExPack

Unified BepInEx all-in-one modding pack - plugin framework, detour library

Preferred version: 5.4.2122

README

UnlockChecklist

Tag locked skills, skins and survivors in the character select, then read the unlock requirements back as a checklist in game.

Status: v0.1.0 — feature complete

Open the loadout panel on the character select screen and click a locked skill. Press K in a run to see what you tagged and what each one needs. Entries tick themselves off as you unlock them.

The mod is client-side and read-only with respect to game state: no netcode, no grants, no patches that change behaviour. The only thing it writes is its own tag list.

How it works

Tagging

Locked entries in the vanilla loadout panel are already click-dead. AddButton sets MPButton.disablePointerClick on anything you have not unlocked, so MPButton.OnPointerClick returns without doing anything — the button exists to show you a lock icon and a tooltip, nothing more. That makes plain left-click a free gesture on exactly the entries this mod cares about, with no vanilla behaviour to override.

The click is picked up by an IPointerClickHandler on the button rather than through onClick. The event system dispatches to every handler component on the object, so the marker hears a click the button itself has decided to ignore. Right-click works everywhere, locked or not, and is dispatched because MPInputModule.GetMousePointerEventData builds a full right-button event from the left button's raycast.

Both gestures are individually switchable in the config.

Finding out what a button stands for

Two postfixes, on LoadoutPanelController.Rebuild and SurvivorIconController.Rebuild. A postfix only adds, and runs after every other mod's patches on the same method, so whatever they did to the rows is what gets decorated. Both bodies are wrapped: seven mods in this profile patch LoadoutPanelController, and an exception thrown from here would surface as their bug.

Survivors are easy — SurvivorIconController.survivorDef is public.

The loadout panel is not. Its buttons live in a private List<Row> of a private nested type, so reading them needs reflection on rows, Row.rowData, RowData.button and RowData.defIndex. That list is used rather than walking the transform children because it carries each button's defIndex, which stays correct when another mod reorders or filters a row. If those fields ever disappear, loadout tagging switches itself off and says so; survivor tagging and the console commands carry on.

Nothing in a row says which skill slot it belongs to — only its position does. Rebuild adds one row per GenericSkill that is not hideInLoadoutSelect, in component order, then exactly one skin row. That enumeration is mirrored to turn a row position back into a slot. If the panel is not that shape, some other mod has added or removed rows and every position past that point means something else, so the panel is skipped with a warning rather than decorated with a wrong mapping. ExtraSkillSlots adds GenericSkill components to the body prefab, so it adds rows and slots and the shape still matches.

Reading the requirement back

UnlockableDef.getHowToUnlockString() is what the game's own tooltip prints, and it is the fallback here. Where the unlockable is backed by an achievement — which is nearly all of them — AchievementManager.GetAchievementDefFromUnlockable gives the name and description separately, which is better: the name is already shown as the row title, so only the description needs to be the requirement line. The achievement icon comes from the same place, falling back to the skill or skin icon when it has none.

What is stored

Only the UnlockableDef name. Which survivor owns it, what the requirement is, which icon to draw and whether it is done are all resolved live from the catalogs, so a tag cannot go stale against a changed modpack.

A name that no longer resolves is kept and shown as unresolved rather than dropped — temporarily disabling a mod should not silently delete your list.

That last point needs one piece of care. UserProfile.HasUnlockable(string) answers true for a name it has never heard of. Passing tag names straight through would mark everything from an uninstalled mod as completed, and Clear completed would then delete it. The def is resolved first instead, and an unresolved one counts as not unlocked.

The list lives in BepInEx/config/com.bdub.UnlockChecklist.tags.txt, one name per line, safe to edit by hand.

The checklist window

K by default, rebindable, and it works in a run, in the lobby and in the main menu. The hotkey stands down while the console, the chat box or any other text field has focus.

It is a standalone overlay canvas rather than something parented into the HUD or the character select hierarchy. The same window then opens on every screen with no per-screen special cases, and nothing another mod does to those hierarchies can reach it.

Bounding

Three things keep rows inside the mask, all of which bit once:

  • A fresh RectTransform is 100x100, and on a stretched rect sizeDelta is not the size — it is added to whatever the anchors span, with the pivot deciding which edges the surplus hangs off. Left at the default on the scroll content, that put 50px of every row past each side of the RectMask2D. CreateChildRect now zeroes it, and the content rect states it again because that is the rect the mask clips against.
  • Labels do not wrap. Every one is a single line in a rect of fixed height, so wrapping would push a second line somewhere too short to show it and slice the glyphs. ConfigureText turns wrapping off and sets Ellipsis for all of them; the row title additionally auto-sizes down to 15pt before truncating, since Survivor - Skill (Slot) gets long on modded content.
  • The list is sized to a whole number of rows. Whole rows are dropped until it fits rather than capping the total height — shaving an arbitrary number of pixels is what leaves a row sliced through the middle, which reads as broken instead of scrollable.

Outstanding entries come first, completed ones after them, struck through with a DONE badge. Unlock state is re-checked once a second while the window is open, so an achievement that fires mid-run ticks itself off without rebuilding the list under you. Rows are only rebuilt when the tag set actually changes.

Console commands

Command Effect
uc_ui Open/close the checklist window
uc_list List everything tagged, with its requirement
uc_tag <name|search> Add something. Accepts Skills.Loader.Thunderslam or thunderslam
uc_untag <name|search> Remove something
uc_find <search> Search unlockables without tagging
uc_clear [done] Empty the list, or only what is completed

Searches that match more than one thing print the candidates instead of guessing. These are the fallback the UI hooks do not have: if a game patch or another mod breaks the character-select decoration, the list stays fully usable.

Open the in-game console with Ctrl + Alt + `` (left Ctrl/Alt) once; after that plain `` orF2` toggles it.

Configuration

General holds ToggleKey, the two tagging gestures (TagOnLeftClickWhenLocked, TagOnRightClick) and ShowCompleted. Display holds MarkTaggedInMenu (the orange corner pip and tint) and AppendTooltipHint.

The tooltip hint is appended to tooltips the game has already filled in, which is only ever locked entries. Rebuild rewrites that text from scratch every time, so it appends once rather than accumulating. Its wording is deliberately stateless — the string is baked at rebuild time but read on hover, so anything naming the current tag state would be wrong the moment you clicked.

Known limitations

  • Only what the loadout panel shows can be tagged: survivors, skill variants and skins. Items, equipment, artifacts and logbook entries have unlockables too, but no screen this mod hooks displays them.
  • Entries with no UnlockableDef are not taggable. There is no requirement to put on a checklist. Most modded survivors ship no unlock at all.
  • Tags are shared by every local profile. RoR2 supports several; a checklist is a note to the person playing, not to the save file.
  • Unlock state is read from local profiles, like everything client-side. In multiplayer you see your own progress, not anyone else's, and nothing is synced — each player's checklist is their own.
  • Achievement progress is not shown, only the requirement text. RoR2 does not expose a general progress figure for an achievement.
  • AchievementDef.GetAchievedIcon() cannot resolve an addressable icon synchronously, so a few modded achievements fall back to the skill or skin icon.

Installing

Install with a mod manager (r2modman / Thunderstore Mod Manager), or drop the DLL into BepInEx/plugins/.

Credits

Written by bdub, with Claude (Anthropic) as a coding assistant.

CHANGELOG

Changelog

0.1.1

  • Rewrote the description and mod page.

0.1.0

  • First release. Loadout-panel tagging, the checklist window (K), and the uc_* console commands.