public static PropertyCollection getDefaultStructValue(string className, bool stripTransients) { bool isImmutable = UnrealObjectInfo.IsImmutable(className, MEGame.ME1); if (Structs.ContainsKey(className)) { ClassInfo info = Structs[className]; try { PropertyCollection structProps = new PropertyCollection(); ClassInfo tempInfo = info; while (tempInfo != null) { foreach ((string propName, PropertyInfo propInfo) in tempInfo.properties) { if (stripTransients && propInfo.Transient) { continue; } if (getDefaultProperty(propName, propInfo, stripTransients, isImmutable) is UProperty uProp) { structProps.Add(uProp); } } if (!Structs.TryGetValue(tempInfo.baseClass, out tempInfo)) { tempInfo = null; } } structProps.Add(new NoneProperty()); string filepath = Path.Combine(ME1Directory.gamePath, "BioGame", info.pccPath); if (File.Exists(info.pccPath)) { filepath = info.pccPath; //Used for dynamic lookup } if (File.Exists(filepath)) { IMEPackage importPCC = MEPackageHandler.OpenME1Package(filepath); var exportToRead = importPCC.getUExport(info.exportIndex); byte[] buff = exportToRead.Data.Skip(0x30).ToArray(); PropertyCollection defaults = PropertyCollection.ReadProps(exportToRead, new MemoryStream(buff), className); foreach (var prop in defaults) { structProps.TryReplaceProp(prop); } } return(structProps); } catch { return(null); } } return(null); }
public static List <ClassInfo> GetSequenceConditions(MEGame game) { List <ClassInfo> classes = UnrealObjectInfo.GetNonAbstractDerivedClassesOf(SequenceConditionName, game); if (game == MEGame.ME2) { return(classes.Where(info => EntryImporter.CanImport(info, MEGame.ME2)).ToList()); } return(classes); }
public static void TrashIncompatibleEntries(MEPackage pcc, MEGame oldGame, MEGame newGame) { var entries = new EntryCollection(pcc); var oldClasses = UnrealObjectInfo.GetClasses(oldGame); var newClasses = UnrealObjectInfo.GetClasses(newGame); var classesToRemove = oldClasses.Keys.Except(newClasses.Keys).ToHashSet(); foreach (IEntry entry in entries) { if (classesToRemove.Contains(entry.ClassName) || (entry.ClassName == "Class" && classesToRemove.Contains(entry.ObjectName)) || entry is ExportEntry exp && (pcc.getEntry(exp.idxArchtype)?.IsTrash() ?? false)) { TrashEntries(pcc, entries.FlattenTree(entry.UIndex)); } } }
public static List <ClassInfo> GetCommonObjects(MEGame game) { return(new List <string> { "Sequence", "SeqAct_Interp", "InterpData", "BioSeqAct_EndCurrentConvNode", "BioSeqEvt_ConvNode", "BioSeqVar_ObjectFindByTag", "SeqVar_Object", "SeqAct_ActivateRemoteEvent", "SeqEvent_SequenceActivated", "SeqAct_Delay", "SeqAct_Gate", "BioSeqAct_PMCheckState", "BioSeqAct_PMExecuteTransition", "SeqAct_FinishSequence" }.Select(className => UnrealObjectInfo.GetClassOrStructInfo(game, className)).NonNull().ToList()); }
public bool TryGetPropInfo(string name, Mod.MEGame game, out PropertyInfo propInfo) => properties.TryGetValue(name, out propInfo) || (UnrealObjectInfo.GetClassOrStructInfo(game, baseClass)?.TryGetPropInfo(name, game, out propInfo) ?? false);
public static IEntry EnsureClassIsInFile(IMEPackage pcc, string className) { //check to see class is already in file foreach (ImportEntry import in pcc.Imports) { if (import.IsClass && import.ObjectName == className) { return(import); } } foreach (ExportEntry export in pcc.Exports) { if (export.IsClass && export.ObjectName == className) { return(export); } } ClassInfo info = UnrealObjectInfo.GetClassOrStructInfo(pcc.Game, className); //backup some package state so we can undo changes if something goes wrong int exportCount = pcc.ExportCount; int importCount = pcc.ImportCount; List <string> nameListBackup = pcc.Names.ToList(); try { if (EntryImporter.IsSafeToImportFrom(info.pccPath, pcc.Game)) { string package = Path.GetFileNameWithoutExtension(info.pccPath); return(pcc.getEntryOrAddImport($"{package}.{className}")); } //It's a class that's defined locally in every file that uses it. Stream loadStream = null; if (info.pccPath == UnrealObjectInfo.Me3ExplorerCustomNativeAdditionsName) { loadStream = Utilities.GetCustomAppResourceStream(pcc.Game); //string resourceFilePath = App.CustomResourceFilePath(pcc.Game); //if (File.Exists(resourceFilePath)) //{ // sourceFilePath = resourceFilePath; //} } else { string testPath = Path.Combine(MEDirectories.GetBioGamePath(pcc.Game), info.pccPath); if (File.Exists(testPath)) { loadStream = new MemoryStream(File.ReadAllBytes(testPath)); } else if (pcc.Game == MEGame.ME1) { testPath = Path.Combine(ME1Directory.DefaultGamePath, info.pccPath); if (File.Exists(testPath)) { loadStream = new MemoryStream(File.ReadAllBytes(testPath)); } } } if (loadStream == null) { //can't find file to import from. This may occur if user does not have game or neccesary dlc installed return(null); } using IMEPackage sourcePackage = MEPackageHandler.OpenMEPackageFromStream(loadStream); if (!sourcePackage.IsUExport(info.exportIndex)) { return(null); //not sure how this would happen } ExportEntry sourceClassExport = sourcePackage.GetUExport(info.exportIndex); if (sourceClassExport.ObjectName != className) { return(null); } //Will make sure that, if the class is in a package, that package will exist in pcc IEntry parent = EntryImporter.GetOrAddCrossImportOrPackage(sourceClassExport.ParentFullPath, sourcePackage, pcc); var relinkResults = EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, sourceClassExport, pcc, parent, true, out IEntry result); if (relinkResults?.Count > 0) { ListDialog ld = new ListDialog(relinkResults, "Relink report", "The following items failed to relink.", null); ld.Show(); } return(result); } catch (Exception e) { //remove added entries var entriesToRemove = new List <IEntry>(); for (int i = exportCount; i < pcc.Exports.Count; i++) { entriesToRemove.Add(pcc.Exports[i]); } for (int i = importCount; i < pcc.Imports.Count; i++) { entriesToRemove.Add(pcc.Imports[i]); } EntryPruner.TrashEntries(pcc, entriesToRemove); pcc.restoreNames(nameListBackup); return(null); } }
public static PropertyCollection getDefaultStructValue(string className, bool stripTransients = true) { if (Structs.ContainsKey(className)) { bool immutable = UnrealObjectInfo.isImmutable(className, MEGame.ME2); ClassInfo info = Structs[className]; try { if (info.pccPath != "ME3Explorer_CustomNativeAdditions") { string filepath = (Path.Combine(ME2Directory.gamePath, @"BioGame\" + info.pccPath)); if (File.Exists(info.pccPath)) { filepath = info.pccPath; //Used for dynamic lookup } using (ME2Package importPCC = MEPackageHandler.OpenME2Package(filepath)) { byte[] buff; //Plane and CoverReference inherit from other structs, meaning they don't have default values (who knows why) //thus, I have hardcoded what those default values should be if (className == "Plane") { buff = PlaneDefault; } else if (className == "CoverReference") { buff = CoverReferenceDefault; } else { var exportToRead = importPCC.Exports[info.exportIndex]; buff = exportToRead.Data.Skip(0x30).ToArray(); } PropertyCollection props = PropertyCollection.ReadProps(importPCC, new MemoryStream(buff), className); if (stripTransients) { var toRemove = new List <UProperty>(); foreach (var prop in props) { //remove transient props if (info.properties.TryGetValue(prop.Name, out PropertyInfo propInfo)) { if (propInfo.transient) { toRemove.Add(prop); } } //if (!info.properties.ContainsKey(prop.Name) && info.baseClass == "Class") //{ // toRemove.Add(prop); //} } foreach (var prop in toRemove) { Debug.WriteLine($"ME2: Get Default Struct value ({className}) - removing transient prop: {prop.Name}"); props.Remove(prop); } } return(props); } } } catch { return(null); } } return(null); }
public static UProperty getDefaultProperty(string propName, PropertyInfo propInfo, bool stripTransients = true, bool isImmutable = false) { switch (propInfo.Type) { case PropertyType.IntProperty: return(new IntProperty(0, propName)); case PropertyType.FloatProperty: return(new FloatProperty(0f, propName)); case PropertyType.DelegateProperty: return(new DelegateProperty(0, "None")); case PropertyType.ObjectProperty: return(new ObjectProperty(0, propName)); case PropertyType.NameProperty: return(new NameProperty("None", propName)); case PropertyType.BoolProperty: return(new BoolProperty(false, propName)); case PropertyType.ByteProperty when propInfo.IsEnumProp(): return(new EnumProperty(propInfo.Reference, MEGame.ME2, propName)); case PropertyType.ByteProperty: return(new ByteProperty(0, propName)); case PropertyType.StrProperty: return(new StrProperty("", propName)); case PropertyType.StringRefProperty: return(new StringRefProperty(propName)); case PropertyType.BioMask4Property: return(new BioMask4Property(0, propName)); case PropertyType.ArrayProperty: switch (getArrayType(propInfo)) { case ArrayType.Object: return(new ArrayProperty <ObjectProperty>(propName)); case ArrayType.Name: return(new ArrayProperty <NameProperty>(propName)); case ArrayType.Enum: return(new ArrayProperty <EnumProperty>(propName)); case ArrayType.Struct: return(new ArrayProperty <StructProperty>(propName)); case ArrayType.Bool: return(new ArrayProperty <BoolProperty>(propName)); case ArrayType.String: return(new ArrayProperty <StrProperty>(propName)); case ArrayType.Float: return(new ArrayProperty <FloatProperty>(propName)); case ArrayType.Int: return(new ArrayProperty <IntProperty>(propName)); case ArrayType.Byte: return(new ImmutableByteArrayProperty(propName)); default: return(null); } case PropertyType.StructProperty: isImmutable = isImmutable || UnrealObjectInfo.IsImmutable(propInfo.Reference, MEGame.ME2); return(new StructProperty(propInfo.Reference, getDefaultStructValue(propInfo.Reference, stripTransients), propName, isImmutable)); case PropertyType.None: case PropertyType.Unknown: default: return(null); } }
public static PropertyCollection GetSequenceObjectDefaults(IMEPackage pcc, ClassInfo info) { MEGame game = pcc.Game; PropertyCollection defaults = new PropertyCollection(); if (info.ClassName == "Sequence") { defaults.Add(new ArrayProperty <ObjectProperty>("SequenceObjects")); } else if (!info.IsA(SequenceVariableName, game)) { ArrayProperty <StructProperty> varLinksProp = null; ArrayProperty <StructProperty> outLinksProp = null; ArrayProperty <StructProperty> eventLinksProp = null; ArrayProperty <StructProperty> inLinksProp = null; Dictionary <string, ClassInfo> classes = UnrealObjectInfo.GetClasses(game); try { ClassInfo classInfo = info; while (classInfo != null && (varLinksProp is null || outLinksProp is null || eventLinksProp is null || game == MEGame.ME1 && inLinksProp is null)) { string filepath = Path.Combine(MEDirectories.GetBioGamePath(game), classInfo.pccPath); Stream loadStream = null; if (File.Exists(classInfo.pccPath)) { loadStream = new MemoryStream(File.ReadAllBytes(classInfo.pccPath)); } else if (classInfo.pccPath == UnrealObjectInfo.Me3ExplorerCustomNativeAdditionsName) { loadStream = Utilities.GetCustomAppResourceStream(game); } else if (File.Exists(filepath)) { loadStream = new MemoryStream(File.ReadAllBytes(filepath)); } else if (game == MEGame.ME1) { filepath = Path.Combine(ME1Directory.DefaultGamePath, classInfo.pccPath); //for files from ME1 DLC if (File.Exists(filepath)) { loadStream = new MemoryStream(File.ReadAllBytes(filepath)); } } if (loadStream != null) { using IMEPackage importPCC = MEPackageHandler.OpenMEPackageFromStream(loadStream); ExportEntry classExport = importPCC.GetUExport(classInfo.exportIndex); UClass classBin = ObjectBinary.From <UClass>(classExport); ExportEntry classDefaults = importPCC.GetUExport(classBin.Defaults); foreach (var prop in classDefaults.GetProperties()) { if (varLinksProp == null && prop.Name == "VariableLinks" && prop is ArrayProperty <StructProperty> vlp) { varLinksProp = vlp; //relink ExpectedType foreach (StructProperty varLink in varLinksProp) { if (varLink.GetProp <ObjectProperty>("ExpectedType") is ObjectProperty expectedTypeProp && importPCC.TryGetEntry(expectedTypeProp.Value, out IEntry expectedVar) && EntryImporterExtended.EnsureClassIsInFile(pcc, expectedVar.ObjectName) is IEntry portedExpectedVar) { expectedTypeProp.Value = portedExpectedVar.UIndex; } } } if (outLinksProp == null && prop.Name == "OutputLinks" && prop is ArrayProperty <StructProperty> olp) { outLinksProp = olp; } if (eventLinksProp == null && prop.Name == "EventLinks" && prop is ArrayProperty <StructProperty> elp) { eventLinksProp = elp; //relink ExpectedType foreach (StructProperty eventLink in eventLinksProp) { if (eventLink.GetProp <ObjectProperty>("ExpectedType") is ObjectProperty expectedTypeProp && importPCC.TryGetEntry(expectedTypeProp.Value, out IEntry expectedVar) && EntryImporterExtended.EnsureClassIsInFile(pcc, expectedVar.ObjectName) is IEntry portedExpectedVar) { expectedTypeProp.Value = portedExpectedVar.UIndex; } } } if (game == MEGame.ME1 && inLinksProp is null && prop.Name == "InputLinks" && prop is ArrayProperty <StructProperty> ilp) { inLinksProp = ilp; } } } classes.TryGetValue(classInfo.baseClass, out classInfo); } } catch { // ignored } if (varLinksProp != null) { defaults.Add(varLinksProp); } if (outLinksProp != null) { defaults.Add(outLinksProp); } if (eventLinksProp != null) { defaults.Add(eventLinksProp); } if (inLinksProp != null) { defaults.Add(inLinksProp); } //remove links if empty if (defaults.GetProp <ArrayProperty <StructProperty> >("OutputLinks") is { } outLinks&& outLinks.IsEmpty()) { defaults.Remove(outLinks); } if (defaults.GetProp <ArrayProperty <StructProperty> >("VariableLinks") is { } varLinks&& varLinks.IsEmpty()) { defaults.Remove(varLinks); } if (defaults.GetProp <ArrayProperty <StructProperty> >("EventLinks") is { } eventLinks&& eventLinks.IsEmpty()) { defaults.Remove(eventLinks); } if (defaults.GetProp <ArrayProperty <StructProperty> >("InputLinks") is { } inputLinks&& inputLinks.IsEmpty()) { defaults.Remove(inputLinks); } } int objInstanceVersion = UnrealObjectInfo.getSequenceObjectInfo(game, info.ClassName)?.ObjInstanceVersion ?? 1; defaults.Add(new IntProperty(objInstanceVersion, "ObjInstanceVersion")); return(defaults); }
public static PropertyCollection GetSequenceObjectDefaults(IMEPackage pcc, string className, MEGame game) => GetSequenceObjectDefaults(pcc, UnrealObjectInfo.GetClassOrStructInfo(game, className));
public static List <ClassInfo> GetSequenceConditions(MEGame game) { List <ClassInfo> classes = UnrealObjectInfo.GetNonAbstractDerivedClassesOf(SequenceConditionName, game); return(classes); }
public static PropertyCollection RemoveIncompatibleProperties(IMEPackage sourcePcc, PropertyCollection props, string typeName, MEGame newGame) { var infoProps = UnrealObjectInfo.GetAllProperties(newGame, typeName); var newProps = new PropertyCollection(); foreach (UProperty prop in props) { if (infoProps.ContainsKey(prop.Name)) { switch (prop) { case ArrayProperty <DelegateProperty> adp: //don't think these exist? if they do, delete them break; case ArrayProperty <EnumProperty> aep: if (UnrealObjectInfo.GetEnumValues(newGame, aep.Reference) is List <NameReference> enumValues) { foreach (EnumProperty enumProperty in aep) { if (!enumValues.Contains(enumProperty.Value)) { enumProperty.Value = enumValues.First(); //hope that the first value is a reasonable default } } newProps.Add(aep); } break; case ArrayProperty <ObjectProperty> asp: for (int i = asp.Count - 1; i >= 0; i--) { if (asp[i].Value == 0 || sourcePcc.getEntry(asp[i].Value) is IEntry entry && !entry.GetFullPath.StartsWith(UnrealPackageFile.TrashPackageName)) { continue; } //delete if it references a trashed entry or if value is invalid asp.RemoveAt(i); } newProps.Add(asp); break; case ArrayProperty <StructProperty> asp: if (UnrealObjectInfo.GetStructs(newGame).ContainsKey(asp.Reference)) { if (HasIncompatibleImmutabilities(asp.Reference, out bool newImmutability)) { break; } foreach (StructProperty structProperty in asp) { structProperty.Properties = RemoveIncompatibleProperties(sourcePcc, structProperty.Properties, structProperty.StructType, newGame); structProperty.IsImmutable = newImmutability; } newProps.Add(asp); } break; case DelegateProperty delegateProperty: //script related, so just delete it. break; case EnumProperty enumProperty: if (UnrealObjectInfo.GetEnumValues(newGame, enumProperty.EnumType) is List <NameReference> values) { if (!values.Contains(enumProperty.Value)) { enumProperty.Value = values.First(); //hope that the first value is a reasonable default } newProps.Add(enumProperty); } break; case ObjectProperty objectProperty: { if (objectProperty.Value == 0 || sourcePcc.getEntry(objectProperty.Value) is IEntry entry && !entry.GetFullPath.StartsWith(UnrealPackageFile.TrashPackageName)) { newProps.Add(objectProperty); } break; } case StructProperty structProperty: string structType = structProperty.StructType; if (UnrealObjectInfo.GetStructs(newGame).ContainsKey(structType)) { if (HasIncompatibleImmutabilities(structType, out bool newImmutability)) { break; } structProperty.Properties = RemoveIncompatibleProperties(sourcePcc, structProperty.Properties, structType, newGame); structProperty.IsImmutable = newImmutability; newProps.Add(structProperty); } break; default: newProps.Add(prop); break; } } } return(newProps); bool HasIncompatibleImmutabilities(string structType, out bool newImmutability) { bool sourceIsImmutable = UnrealObjectInfo.IsImmutable(structType, sourcePcc.Game); newImmutability = UnrealObjectInfo.IsImmutable(structType, newGame); if (sourceIsImmutable && newImmutability && !UnrealObjectInfo.GetClassOrStructInfo(sourcePcc.Game, structType).properties .SequenceEqual(UnrealObjectInfo.GetClassOrStructInfo(newGame, structType).properties)) { //both immutable, but have different properties return(true); } if (!sourceIsImmutable && newImmutability) { //can't easily guarantee it will have have all neccesary properties return(true); } return(false); } }
public static PropertyCollection getDefaultStructValue(string className, bool stripTransients) { bool isImmutable = UnrealObjectInfo.IsImmutable(className, MEGame.ME2); if (Structs.ContainsKey(className)) { ClassInfo info = Structs[className]; try { PropertyCollection structProps = new PropertyCollection(); ClassInfo tempInfo = info; while (tempInfo != null) { foreach ((string propName, PropertyInfo propInfo) in tempInfo.properties) { if (stripTransients && propInfo.Transient) { continue; } if (getDefaultProperty(propName, propInfo, stripTransients, isImmutable) is Property uProp) { structProps.Add(uProp); } } if (!Structs.TryGetValue(tempInfo.baseClass, out tempInfo)) { tempInfo = null; } } structProps.Add(new NoneProperty()); string filepath = null; if (ME2Directory.BioGamePath != null) { filepath = Path.Combine(ME2Directory.BioGamePath, info.pccPath); } Stream loadStream = null; if (File.Exists(info.pccPath)) { filepath = info.pccPath; loadStream = new MemoryStream(File.ReadAllBytes(info.pccPath)); } else if (info.pccPath == UnrealObjectInfo.Me3ExplorerCustomNativeAdditionsName) { filepath = "GAMERESOURCES_ME2"; loadStream = Utilities.LoadFileFromCompressedResource("GameResources.zip", CoreLib.CustomResourceFileName(MEGame.ME2)); } else if (filepath != null && File.Exists(filepath)) { loadStream = new MemoryStream(File.ReadAllBytes(filepath)); } #if AZURE else if (MiniGameFilesPath != null && File.Exists(Path.Combine(MiniGameFilesPath, info.pccPath))) { // Load from test minigame folder. This is only really useful on azure where we don't have access to // games filepath = Path.Combine(MiniGameFilesPath, info.pccPath); loadStream = new MemoryStream(File.ReadAllBytes(filepath)); } #endif if (loadStream != null) { using (IMEPackage importPCC = MEPackageHandler.OpenMEPackageFromStream(loadStream, filepath, useSharedPackageCache: true)) { var exportToRead = importPCC.GetUExport(info.exportIndex); byte[] buff = exportToRead.Data.Skip(0x30).ToArray(); PropertyCollection defaults = PropertyCollection.ReadProps(exportToRead, new MemoryStream(buff), className); foreach (var prop in defaults) { structProps.TryReplaceProp(prop); } } } return(structProps); } catch { return(null); } } return(null); }