Add UE 5.8 support: custom versions and cooked FField flags removal - #156
Open
stevenlafl wants to merge 1 commit into
Open
stevenlafl wants to merge 1 commit into
stevenlafl wants to merge 1 commit into
Conversation
stevenlafl
force-pushed
the
ue5.8-cooked-support
branch
from
September 1, 2026 05:41
3324b41 to
53dd57b
Compare
…lying type - Add the 53 custom version entries introduced in UE 5.8 (43x FFortniteMainBranchObjectVersion, 7x FUE5ReleaseStreamObjectVersion, 3x FFortniteReleaseBranchCustomObjectVersion), annotated [Introduced(EngineVersion.VER_UE5_8)]. UE 5.8 added no new EUnrealEngineObjectUE5Version entries, so these custom versions are what makes VER_UE5_8 distinguishable from VER_UE5_7. - As of UE 5.8, FField::Serialize no longer serializes FlagsPrivate into filter-editor-only (cooked) archives; reading a 5.8-cooked package with the old layout misparses every Function/Class/Struct export's property chain. Add FField.SerializesFieldFlags and gate read/write symmetrically. - As of UE 5.8, UEnum::Serialize reads/writes a 1-byte underlying type when FFortniteMainBranchObjectVersion >= EnumUnderlyingType. Mirror in UEnum with an EEnumUnderlyingType enum under the same gate. - Fix GetIntroducedFromCustomVersionValue resolving a value to the VersionPlusOne/LatestVersion sentinel aliases; prefer the real entry sharing the value, and contribute no version constraint when only a sentinel matches. Previously a sentinel's automatic-version attribute could poison the introduction range and force fallback resolution. - Fix GuessCustomVersionFromTypeAndEngineVersion returning an index into its name array instead of the enum value, walking names in unsigned order (negative sentinels last). FInstancedStructCustomVersion previously guessed a container value of 1, which does not exist in that enum; it now guesses 0 for engines >= 5.3 and omits the version before it existed.
stevenlafl
force-pushed
the
ue5.8-cooked-support
branch
from
September 1, 2026 06:29
53dd57b to
681ac81
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First off, feel free to close it upon reading the disclosure section. I have a feeling what's done here will be done by someone else in the future anyways; in any case, to get this working fast for anyone comes along and wants it (and the work still isn't done), here it is for those users. I used it when patching DML and Dev Menu for The Last Caretaker and it works in-game after the latest 5.8 update.
Add UE 5.8 support: custom versions and cooked FField flags removal
This PR makes UAssetAPI able to correctly parse UE 5.8-cooked packages, which currently misparse in three related ways.
1. VER_UE5_8 custom version data (
CustomVersions.cs)UE 5.8 did not add any new
EUnrealEngineObjectUE5Versionentries, so 5.7 and 5.8 share the sameObjectVersionUE5and were previously indistinguishable:SetEngineVersion(VER_UE5_8)followed byGetEngineVersion()returnedVER_UE5_7. 5.8 did, however, bump several custom version enums. This adds the 53 new entries (43xFFortniteMainBranchObjectVersion, 7xFUE5ReleaseStreamObjectVersion, 3xFFortniteReleaseBranchCustomObjectVersion) annotated[Introduced(EngineVersion.VER_UE5_8)], mirrored from the corresponding*ObjectVersions.inlheaders in the 5.8 release branch. With these, engine-version round-trips resolve correctly and versioned 5.8 assets can be auto-detected.2. FField flags are no longer serialized in cooked packages (
FField.cs)As of UE 5.8,
FField::Serializeonly serializesFlagsPrivatewhen!Ar.IsFilterEditorOnly()(on load it reads into a discarded dummy under the same condition). Cooked packages are filter-editor-only, so everyFFieldin a 5.8-cooked package is 4 bytes shorter than before. Reading such a package with the old layout shifts every subsequent field in each Function/Class/Struct export's property chain. In-game this class of mismatch manifests asObjectSerializationError ... Bad name indexwhen older cooked data meets a newer runtime, and in UAssetAPI as garbageSerializedTypenames.Added
FField.SerializesFieldFlags(UAsset): flags are serialized unless the asset is filter-editor-only andGetEngineVersion() >= VER_UE5_8. Read and Write are gated symmetrically, so 5.7-and-earlier assets and uncooked 5.8 assets are byte-identical to before.3. UEnum underlying type (
EnumExport.cs)As of UE 5.8,
UEnum::Serializereads/writes a 1-byte underlying type whenFFortniteMainBranchObjectVersion >= EnumUnderlyingType(one of the entries added in section 1). Mirrored inUEnumwith anEEnumUnderlyingTypeenum, gated on the same custom version, so Enum/UserDefinedEnum exports in 5.8 assets parse and round-trip correctly.4. Version resolution fixes (
UAsset.cs)Two pre-existing issues surfaced while making VER_UE5_8 resolvable:
Sentinel alias in
GetIntroducedFromCustomVersionValue:Enum.GetNameon a custom version value can resolve to theVersionPlusOne/LatestVersionaliases instead of the real entry sharing that value (which one wins is unspecified for duplicated enum values). TheirVER_UE4_AUTOMATIC_VERSION(_PLUS_ONE)attributes then poison the min/max introduction range inGetEngineVersion, forcing the object-version-only fallback. This became visible with this PR (VER_UE5_8 resolution depends on the custom-version range), but is a pre-existing issue; e.g.FInstancedStructCustomVersionresolves its container value toVersionPlusOnetoday. Now the real entry is preferred, and a bare sentinel match contributes no constraint.Index-vs-value in
GuessCustomVersionFromTypeAndEngineVersion: it returned the index into its name array rather than the enum value, and walked names inEnum.GetNamesorder (unsigned value order, putting negative sentinels likeBeforeCustomVersionWasAdded = -1last). ForFInstancedStructCustomVersionthis produced a default container value of 1, which does not exist in that enum. It now walks entries in numeric value order and returns the actual value; containers get 0 for engines 5.3 and newer, and omit the version before it existed.Testing
SetEngineVersion/GetEngineVersionround-trips verified for VER_UE4_27 and VER_UE5_3 through VER_UE5_8.EnumUnderlyingTypegate verified to be inactive at VER_UE5_7 and active at VER_UE5_8.Disclosure: human/AI split
This work was done in a Claude Code session driven by me. To be transparent about what that means here:
Done by me (human): initiating and directing the investigation (the motivating case was a UE 5.7.4 -> 5.8.1 game update breaking cooked pak mods), providing licensed UE source access for verification, running every in-game test iteration against the 5.8.1 runtime that the failure analysis and final validation rest on, reviewing the full diff and this description, and deciding what to upstream.
Done by the AI assistant: the binary format analysis (diffing cooked exports between the 5.7 and 5.8 cooks of the same title, correlating with the corresponding serializer changes in UE source), authoring the code changes in this PR, and running the test suite and the version-resolution/flags-gating checks described above.
Everything in this PR was verified against real cooked data and the engine source rather than taken on the model's word; I'm happy to answer questions or rework any of it.