I wonder how you came to that conclusion ? That’s only a limitation of the launcher version. The custom build supports downgrading to 4.27 with the mention that there will be missing nodes if you actually used any of the newer nodes introduced in 5.0-5.7 .
I probably misworded what I wanted to say. I heard that this great plugin exports simpler assets like textures, maps, or materials, but when it comes to blueprints - even using your custom Unreal Engine builds - it often fails, particularly if the project uses plugins. Are there any special steps to make blueprints compatible or “depluginify” them?
Once again, amazing work you did there, this plugin should come bundled with default Unreal Engine install, because it’s so crucial.
I wonder where that “often fails” comes from because I fixed everything that was sent to me so far. If the project uses plugins and those plugins existed on the prior versions, it will definitely work, unless the interface changed dramatically. If the plugin doesn’t exist (like ACL) It will still work because I added fixes in, but in most cases if the dependency is really strong, like the base class of the blueprint is based off a plugin class and that plugin doesn’t exist, then yeah, the blueprint is unusable. But even then there are workarounds, like if the plugin is entirely asset based like the interchange plugin you can downgrade the plugin assets and then move the entire plugin to the lower version and it will still work as I’ve already done this.
Ok, then maybe you can record a better more indepth video tutorial? That starts from unpacking and naming plugin folders properly, then downgrading big (5.X projects to 4.26) on systems with 16 gb of ram or less, then launching the destination project and resaving and depluginifying. I assume if people fail one step - entire chain fails?
Btw do have any plans for 4.24? I have gathered some codes from internet for 4.27 and tried to convert them to 4.24 [some codes are missing or incorrect]
4.27
from pathlib import Path
import binascii
bytes_to_read = 2000
guids = {
"Dev-Blueprints": "B0D832E41F894F0DACCF7EB736FD4AA2",
"Dev-Build": "E1C64328A22C4D53A36C8E866417BD8C",
"Dev-Core": "375EC13C06E448FBB50084F0262A717E",
"Dev-Editor": "E4B068EDF49442E9A231DA0B2E46BB41",
"Dev-Framework": "CFFC743F43B04480939114DF171D2073",
"Dev-Mobile": "B02B49B5BB2044E9A30432B752E40360",
"Dev-Networking": "A4E4105C59A149B5A7C540C4547EDFEE",
"Dev-Online": "39C831C95AE647DC9A449C173E1C8E7C",
"Dev-Physics": "78F01B33EBEA4F98B9B484EACCB95AA2",
"Dev-Platform": "6631380F2D4D43E08009CF276956A95A",
"Dev-Rendering": "12F88B9F88754AFCA67CD90C383ABD29",
"Dev-Sequencer": "7B5AE74CD2704C10A95857980B212A5A",
"Dev-VR": "D72969181DD64BDD9DE264A83CC13884",
"Dev-LoadTimes": "C2A15278BFE74AFE6C1790FF531DF755",
"Private-Geometry": "6EACA3D440EC4CC1b7868BED09428FC5",
"Dev-AnimPhys": "29E575DDE0A346279D10D276232CDCEA",
"Dev-Anim": "AF43A65D7FD3494798733E8ED9C1BB05",
"Dev-ReflectionCapture": "6B266CEC1EC74B8FA30BE4D90942FC07",
"Dev-Automation": "0DF73D61A23F47EAB72789E90C41499A",
"FortniteMain": "601D1886AC644F84AA16D3DE0DEAC7D6",
"FortniteRelease": "E70863686B234C5884391B7016265E91",
"Dev-Enterprise": "9DFFBCD6494F0158E22112823C92A888",
"Dev-Niagara": "F2AED0AC9AFE416F8664AA7FFA26D6FC",
"Dev-Destruction": "174F1F0BB4C645A5B13F2EE8D0FB917D",
"Dev-Physics-Ext": "35F94A83E258406CA31809F59610247C",
"Dev-PhysicsMaterial-Chaos": "B68FC16E8B1B42E2B453215C058844FE",
"Dev-CineCamera": "B2E185064273CFC2A54EF4BB758BBA07",
"Dev-VirtualProduction": "64F58936FD1B42BABA967289D5D0FA4E",
"Dev-MediaFramework": "6f0ed827a60948959c91998d90180ea4",
"Release": "9C54D522A8264FBE9421074661B482D0",
}
# Leave these at -1 to just read the asset values. Put some other value here to downgrade the custom version to it
updated_values = {
"Dev-Rendering": 44,
"Dev-Physics-Ext": 40,
"FortniteMain": 43,
"Release": 38,
}
target_folder = r"E:\Work\Unreal projects\Retail4262\Content\From427"
asset_types = ["uasset", "umap"]
update_engine_version = True
engine_major_version = 4
engine_minor_version = 26
engine_changelist = 15973114
asset_major_version = 4
asset_minor_version = 27
asset_changelist = 16724560
def collect_files(folder_root, formats):
result = []
for fmt in formats:
for path in Path(folder_root).rglob('*.' + fmt):
result.append(str(path))
return result
def build_version_bytes(major, minor, changelist):
result = bytearray()
result += major.to_bytes(2, byteorder="little") # Major version stored in a short
result += minor.to_bytes(4, byteorder="little") # Minor version stored in an int
result += changelist.to_bytes(4, byteorder="little") # CL stored in an int
return result
def flip_endianess(orig_bytes):
result = bytearray([0]*16)
index = 0
for chunk in range(4):
for byte_index in [3, 2, 1, 0]:
result[index] = orig_bytes[chunk * 4 + byte_index]
index += 1
return result
guids_bytes = {key:flip_endianess(binascii.unhexlify(value)) for (key, value) in guids.items()}
asset_version_bytes = build_version_bytes(asset_major_version, asset_minor_version, asset_changelist)
engine_version_bytes = build_version_bytes(engine_major_version, engine_minor_version, engine_changelist)
assert(len(asset_version_bytes) == len(engine_version_bytes))
for file_path in collect_files(target_folder, asset_types):
print(file_path)
with open(file_path, "r+b") as f:
chunk = f.read(bytes_to_read)
print(f"File: '{file_path}'")
# Update custom versions
for (entry, new_value) in updated_values.items():
guid = guids_bytes[entry]
index = chunk.find(guid)
if index == -1:
print(f"\tCouldn't find custom version '{entry}'")
continue
value_index = index + len(guid)
asset_value = int.from_bytes(chunk[value_index:value_index+4], byteorder="little")
if new_value != -1:
if new_value >= asset_value:
print(f"\tLeft '{entry}' at '{chunk[value_index]}'")
continue
f.seek(value_index)
f.write(new_value.to_bytes(4, byteorder="little"))
print(f"\tDowngraded '{entry}' from '{asset_value}' to '{new_value}'")
else:
print(f"\tRead '{entry}' with value '{asset_value}'")
# Update engine version (we do this twice because we could have engine and "compatible" changelist)
if update_engine_version:
index = chunk.find(asset_version_bytes)
if index != -1:
print(f"\tReplaced first occurence of asset version '{binascii.hexlify(asset_version_bytes)}' with '{binascii.hexlify(engine_version_bytes)}'")
f.seek(index)
f.write(engine_version_bytes)
index = chunk.find(asset_version_bytes, index+1)
if index != -1:
print(f"\tReplaced second occurence of engine version '{binascii.hexlify(asset_version_bytes)}' with '{binascii.hexlify(engine_version_bytes)}'")
f.seek(index)
f.write(engine_version_bytes)
print("")
4.24
from pathlib import Path
import binascii
bytes_to_read = 2000
guids = {
"Dev-Blueprints": "4A8D0FBE4F9A4E40B2507C59D7649EDE",
"Dev-Build": "ABE272B9BFAC401B8B3A19B00530E2CA",
"Dev-Core": "3D83AA544D7246D1A19678C0F0D0B067",
"Dev-Editor": "2B206FCC5C5E456B8E9E58DB1E92722D",
"Dev-Framework": "E5B3E1EE4C9343DDB3AA6788F6DA905E",
"Dev-Mobile": "B50213B4BF7E456695A77B12378688C1",
"Dev-Networking": "A5E8D92A5D1F48B49C0532A1AA0B5A23",
"Dev-Online": "E9062A5E5CBF46178D99904FD9BC27A",
"Dev-Physics": "EBD758474FA54D9AAB7DDF4C3F1F78DD",
"Dev-Platform": "E8A8CB9D461B4DCEB8F1469A8EB4979F",
"Dev-Rendering": "76786D984AD34E97A7F731B7FA3F6A6C",
"Dev-Sequencer": "4B4EE87C4E1F450EA4DA47847B9EB6D2",
"Dev-VR": "D571B84B4F674F4AA7C3A1AD84C7082C",
"Dev-LoadTimes": "C54E6E834C014DD0AF9DFC5C22D85EFD",
"Private-Geometry": "C148FE494C1F4E56B7B5588E285A5D44",
"Dev-AnimPhys": "397E1AD14B3E4A5DB2A0D7D8F15822EF",
"Dev-Anim": "B1DE45A94B8E4A8E962FF68ECCE08E2A",
"Dev-ReflectionCapture": "8C6AC48C4B2747DCA7AED68D7F07A1D2",
"Dev-Automation": "CD4B55E64A9A463D977DD58CCDAE0837",
"FortniteMain": "1C5EDE2B4B944E079AB720E05AB4D61",
"FortniteRelease": "9F24C3374A8A4A40841C44EBD9C7AC57",
"Dev-Enterprise": "BAA05A694■■■441FB10E1C82493F8888",
"Dev-Niagara": "FAFD0A9D4AF14469A6839786FA6760D6",
"Dev-Destruction": "18A511A84B5C4E5AB6F2CF8F5D0EB17D",
"Dev-Physics-Ext": "B5BBABA64B384F6EA3389BF96E09277C",
"Dev-PhysicsMaterial-Chaos": "4B58C5A64B3A4E2B830315C4589845FE",
"Dev-CineCamera": "B4B3BBD74B2C4CF2B5C74BBB75B6BB07",
"Dev-VirtualProduction": "5AB3BDB74B2B4EB2B6B7BBD26BBB1BA4",
"Dev-MediaFramework": "6A0ED827A60948959C91998D90180EA4",
"Release": "FB17BE97A8264E5FA716734A61A742D"
}
# Leave these at -1 to just read the asset values. Put some other value here to downgrade the custom version to it
updated_values = {
"Dev-Rendering": 44,
"Dev-Physics-Ext": 40,
“Dev-Sequencer”: 12,
"FortniteMain": 43,
"Release": 38,
}
target_folder = r"E:\Work\Unreal projects\Retail4262\Content\From427"
asset_types = ["uasset", "umap"]
update_engine_version = True
engine_major_version = 4
engine_minor_version = 24
engine_changelist = 15973114
asset_major_version = 4
asset_minor_version = 24
asset_changelist = 15973114
def collect_files(folder_root, formats):
result = []
for fmt in formats:
for path in Path(folder_root).rglob('*.' + fmt):
result.append(str(path))
return result
def build_version_bytes(major, minor, changelist):
result = bytearray()
result += major.to_bytes(2, byteorder="little") # Major version stored in a short
result += minor.to_bytes(4, byteorder="little") # Minor version stored in an int
result += changelist.to_bytes(4, byteorder="little") # CL stored in an int
return result
def flip_endianess(orig_bytes):
result = bytearray([0]*16)
index = 0
for chunk in range(4):
for byte_index in [3, 2, 1, 0]:
result[index] = orig_bytes[chunk * 4 + byte_index]
index += 1
return result
guids_bytes = {key:flip_endianess(binascii.unhexlify(value)) for (key, value) in guids.items()}
asset_version_bytes = build_version_bytes(asset_major_version, asset_minor_version, asset_changelist)
engine_version_bytes = build_version_bytes(engine_major_version, engine_minor_version, engine_changelist)
assert(len(asset_version_bytes) == len(engine_version_bytes))
for file_path in collect_files(target_folder, asset_types):
print(file_path)
with open(file_path, "r+b") as f:
chunk = f.read(bytes_to_read)
print(f"File: '{file_path}'")
# Update custom versions
for (entry, new_value) in updated_values.items():
guid = guids_bytes[entry]
index = chunk.find(guid)
if index == -1:
print(f"\tCouldn't find custom version '{entry}'")
continue
value_index = index + len(guid)
asset_value = int.from_bytes(chunk[value_index:value_index+4], byteorder="little")
if new_value != -1:
if new_value >= asset_value:
print(f"\tLeft '{entry}' at '{chunk[value_index]}'")
continue
f.seek(value_index)
f.write(new_value.to_bytes(4, byteorder="little"))
print(f"\tDowngraded '{entry}' from '{asset_value}' to '{new_value}'")
else:
print(f"\tRead '{entry}' with value '{asset_value}'")
# Update engine version (we do this twice because we could have engine and "compatible" changelist)
if update_engine_version:
index = chunk.find(asset_version_bytes)
if index != -1:
print(f"\tReplaced first occurence of asset version '{binascii.hexlify(asset_version_bytes)}' with '{binascii.hexlify(engine_version_bytes)}'")
f.seek(index)
f.write(engine_version_bytes)
index = chunk.find(asset_version_bytes, index+1)
if index != -1:
print(f"\tReplaced second occurence of engine version '{binascii.hexlify(asset_version_bytes)}' with '{binascii.hexlify(engine_version_bytes)}'")
f.seek(index)
f.write(engine_version_bytes)
print("")
Yeah, I’ll probably make a new video showing more asset types being downgraded. Problem is I’m too busy fixing reported bugs all the time. And no plans for 4.24, since you’re maybe the second or third person asking for it. I’d have to be heavily financially motivated to add 4.24 support.
I tried with the newest plugin version and a custom engine build.
Face with ARKit is working - that’s cool! But after refreshing “AnimNode_RigLogic” everywhere I could, the BP avatar crashes the engine when I try to spawn or open it.
Turns out it crashes after updating “AnimNode_RigLogic” in the ABP_Body_PostProcess (MetaHumans/Common/Body). Sometimes it crashes after recompiling this ABP or opening BP avatar after refreshing that AnimNode node.
That’s weird…
Update on that reply:
I found an issue that causes UE 5.3 to crash, and another problem that “maybe“ can be fixed.
- I assume that the downgraded skeletal mesh “Body“ has something that causes the crash. From my end, the best approach was to import it as a new body with FBX, which I had exported from 5.7. Then I assigned the post-process anim blueprint “ABP Body Post Process“ with the animating rig “MetaHuman_ControlRig“. Then the control rig worked flawlessly!
- The issue that blocks using this avatar for production is MetaHuman DNA. I saw that face kinda “works“ with all morphs, pose asset, and can be animated with the control rig. BUT, the DNA from 5.7 is incompatible with MetaHuman in the older Unreal Engine, which is why the face is fighting with itself in the “Animation Blueprint” or in the “Level“, something like this:
It can freeze the UE, or move an avatar a bit, and undo changes may show these visual glitches. And yes - without DNA, facial control won’t work anymore with the control rig or using pose asset “mh_arkit“.
Unfortunately, nobody looked at downgrading the MetaHuman DNA from 5.6/5.7, which can work for the older version of UE. Perhaps your plugin does some changes to it, but in the end, I receive these results.
I fixed a crash a few days when downgrading the DNA to 5.4, not sure if that’s impacting 5.3 yet as the same mesh didn’t. And the faces going crazy is also related to DNA downgrading, because the 2.5 DNA version in UE5.5+ added more input data ( rbfControlCount ), and when downgrading to 2.3 for < UE5.5, there’s these “inputindices” that point to an offset inside an input array that assumes those rfbControlPoints are in the beginning of the array, so when that data doesn’t exist (because 2.3 doesn’t know about them), they start pointing to invalid memory. I spent about 3 days trying to figure this one out but it will take more to figure out how to patch those indices so they point to valid offsets.
UPDATE : I added 2 fixes for DNA data in the latest custom build of 5.7.3. One fixes the “inputIndices” to not reference indices that were originally related to that RBF feature. This seems to fix spazzing faces when downgrading to 5.4. Second fix is that I modified the metahuman plugin so that when you click “Create full rig” it requests DNA data without the RBF feature (this is calculated on a server sadly) which can then be safely downgraded to 5.4 without issues.


