egg-placement-geography #2

Merged
brian merged 2 commits from egg-placement-geography into main 2026-08-14 19:34:24 +00:00
Owner
No description provided.
The package always ships thumbnail.png, because that is the name Info.json
carries and what the only other workshop package installed here uses. The
source no longer has to be one: assets/thumbnail.{png,jpg,jpeg,webp} are all
accepted, a PNG is copied through untouched, and anything else is converted
to a 512x512 PNG as the package is staged.

That keeps the file you drop in assets/ the original rather than leaving a
converted copy beside it to go stale the next time you replace it.

Pillow is imported only on the conversion path, so a PNG source -- or no
thumbnail at all -- still builds with nothing installed. When a conversion
is needed and Pillow is missing, the build stops and says so, rather than
quietly shipping the placeholder egg over an image someone put there on
purpose. A copied PNG over Steam's 1 MB preview limit now warns.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
All 18 expeditions are gated behind a tower boss. Each now opens at a
character level instead -- 10 for Verdant Hollow up to 80 for the World Tree
and the whole VeryHard tier -- polled every 30s so levelling up opens what it
should without a restart.

The lock is not in the DataTables, and two play sessions were needed to
establish that. DT_CharacterTeamMissionDataTable names a condition row per
mission and DT_CharacterTeamMissionChallengeConditionDataTable spells out
which tower it means, so the obvious move was to clear both ends. It does
nothing: PalCharacterTeamMissionInfo holds bEnableChallenge already decided,
alongside a *copy* of the master data rather than a reference, so an edit
after the fact cannot move a boolean that has been computed. The menu's
condition text does re-read the table live, which is why blanking
DefeatBossType swapped the tower's name for an untranslated developer
placeholder and left a condition no tower could satisfy -- strictly worse
than vanilla. The technology tree is patchable this way only because it
queries its table at the moment it needs an answer; nothing in a table says
which kind it is.

What does hold the lock is PalGuildCharacterTeamMission.ReleasedMissionInfos,
an array of { MissionId, bEnableChallenge } -- the same state beating a tower
sets. The nine normal missions are present with false, so those flip; the
nine VeryHard ones are absent, so they are appended by clone-then-overwrite,
9 into a capacity of 24 with no reallocation. It only ever writes true, so a
tower beaten early keeps its expedition and nothing is taken away.

This is the first thing here that writes save data, and it persists: an
expedition opened this way stays open with the mod removed. It is the reason
the config block leads with a warning.

A station caches its mission list when it is created, during world load, so
one already standing showed the old locks until it was demolished and rebuilt.
Standing stations are now told to re-read by calling their own OnRep_State and
OnRep_TargetMissionId, which re-broadcast unchanged values; whether the
guild's OnRep_ReleasedMissionInfos lands is logged rather than swallowed,
since a silent failure there looks exactly like a stale station.

Two bugs the mock could not have caught, both since fixed and now covered:
ForEachRow hands back an FName rather than a string, so unlockLevels[name]
missed every key and the game reported "18 open, 0 still level-locked (player
level 38)"; and the array reports DUNGEON_GRASS where the config says
Dungeon_Grass, FName being case-insensitive, so matching folds case. The
mocks now hand out FNames and the loud spelling, and reverting either fix
fails the suite with the same numbers the game printed.

ue4ss/PacifistPalExpeditionProbe/ is the diagnostic that settled it, kept for
the next time: it reads PalDebugSetting.bUnlockAllTeamMission (present in
shipping reflection data, but inert -- the array it should affect stayed
false), dumps the guild array, and lists the candidate classes' functions,
which is how hooking was ruled out. Those classes expose only _ServerInternal
RPCs and OnRep_ handlers; no function computes the lock, so there is nothing
for UE4SS to hook.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
brian merged commit 778d72b9ef into main 2026-08-14 19:34:24 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
brian/PacifistPal!2
No description provided.