public static void AddReferencesToWorld(IMEPackage package, IEnumerable <ExportEntry> newRefs) { var theWorld = package.FindExport("TheWorld"); var world = ObjectBinary.From <World>(theWorld); var extarRefs = world.ExtraReferencedObjects.ToList(); extarRefs.AddRange(newRefs.Select(x => new UIndex(x.UIndex))); world.ExtraReferencedObjects = extarRefs.Distinct().ToArray(); theWorld.WriteBinary(world); }
/// <summary> /// Hack to force power lists to load with only a single check /// </summary> /// <param name="option"></param> /// <returns></returns> public static bool Init(RandomizationOption option) { MERLog.Information(@"Preloading weapon data"); LoadGuns(); WeaponAnimsPackage = MERFileSystem.GetStartupPackage(); WeaponAnimationsArrayProp = WeaponAnimsPackage.FindExport("WeaponAnimData").GetProperty <ArrayProperty <StructProperty> >("WeaponAnimSpecs"); MERLog.Information(@"Installing weapon animations startup package"); MERFileSystem.InstallStartupPackage(); // Contains weapon animations return(true); }
private static void RandomizeArcherFaceColor(IMEPackage package) { var uncMaterials = package.FindExport("BioVFX_Env_UNC_Pack01.Materials"); if (uncMaterials != null) { // Probably should check a bit more than this, such as VI var viMats = package.Exports.Where(x => x.idxLink == uncMaterials.UIndex && x.ClassName == "MaterialInstanceConstant" && ( x.ObjectName.Name.StartsWith("VI_") || x.ObjectName.Name.StartsWith("Line_Sweep") )).ToList(); if (viMats.Any()) { // Generate the color var fullColor = MakeRandomColor(11.2f); foreach (var m in viMats) { var props = m.GetProperties(); var linearColor = props.GetProp <ArrayProperty <StructProperty> >("VectorParameterValues")?[0].GetProp <StructProperty>("ParameterValue"); if (linearColor != null) { if (m.ObjectName.Name.StartsWith("Line")) { // One Tenth color linearColor.Properties.GetProp <FloatProperty>("R").Value = fullColor.X / 10; linearColor.Properties.GetProp <FloatProperty>("G").Value = fullColor.Y / 10; linearColor.Properties.GetProp <FloatProperty>("B").Value = fullColor.Z / 10; } else { // Full color linearColor.Properties.GetProp <FloatProperty>("R").Value = fullColor.X; linearColor.Properties.GetProp <FloatProperty>("G").Value = fullColor.Y; linearColor.Properties.GetProp <FloatProperty>("B").Value = fullColor.Z; } m.WriteProperties(props); } } } } }
public virtual ExportEntry GetAsset(MERPackageCache cache = null) { IMEPackage package = null; if (cache != null) { package = cache.GetCachedPackage(PackageFile); } else { var packageF = MERFileSystem.GetPackageFile(PackageFile); if (packageF != null) { package = MEPackageHandler.OpenMEPackage(packageF); } } return(package?.FindExport(AssetPath)); }
public void ApplyChanges(IMEPackage package, MergeAssetCache1 assetsCache, Mod installingMod, GameTarget gameTarget) { // APPLY PROPERTY UPDATES Log.Information($@"Merging changes into {EntryName}"); var export = package.FindExport(EntryName); if (export == null) { throw new Exception(M3L.GetString(M3L.string_interp_mergefile_couldNotFindExportInPackage, package.FilePath, EntryName)); } if (PropertyUpdates != null) { var props = export.GetProperties(); foreach (var pu in PropertyUpdates) { pu.ApplyUpdate(package, props, this); } export.WriteProperties(props); } // APPLY ASSET UPDATE AssetUpdate?.ApplyUpdate(package, export, installingMod); // APPLY SCRIPT UDPATE ScriptUpdate?.ApplyUpdate(package, export, assetsCache, installingMod, gameTarget); // APPLY SEQUENCE SKIP UPDATE SequenceSkipUpdate?.ApplyUpdate(package, export, installingMod); // APPLY CONFIG FLAG REMOVAL if (DisableConfigUpdate) { DisableConfigFlag(package, export, installingMod); } }
private static void GenericRandomizeFlyerSpawns(IMEPackage package, int maxNumNewEnemies, EPortablePawnClassification minClassification = EPortablePawnClassification.Mook, EPortablePawnClassification maxClassification = EPortablePawnClassification.Boss) { var flyerPrepSequences = package.Exports.Where(x => x.ClassName == "Sequence" && x.GetProperty <StrProperty>("ObjName") is StrProperty objName && objName == "REF_SpawnPrep_Flyer").ToList(); foreach (var flySeq in flyerPrepSequences) { var objectsInSeq = KismetHelper.GetSequenceObjects(flySeq).OfType <ExportEntry>().ToList(); var preGate = objectsInSeq.FirstOrDefault(x => x.ClassName == "SeqAct_Gate"); // should not be null var outbound = SeqTools.GetOutboundLinksOfNode(preGate); var aifactoryObj = outbound[0][0].LinkedOp as ExportEntry; //First out on first link. Should point to AIFactory assuming these are all duplicated flyers var availablePawns = PawnPorting.PortablePawns.Where(x => x.Classification >= minClassification && x.Classification <= maxClassification).ToList(); if (availablePawns.Any()) { // We can add new pawns to install List <PortablePawn> newPawnsInThisSeq = new List <PortablePawn>(); int numEnemies = 1; // 1 is the original amount. List <ExportEntry> aiFactories = new List <ExportEntry>(); aiFactories.Add(aifactoryObj); // the original one for (int i = 0; i < maxNumNewEnemies; i++) { var randPawn = availablePawns.RandomElement(); if (!newPawnsInThisSeq.Contains(randPawn)) { numEnemies++; PawnPorting.PortPawnIntoPackage(randPawn, package); newPawnsInThisSeq.Add(randPawn); // Clone the ai factory sequence object and add it to the sequence var newAiFactorySeqObj = EntryCloner.CloneTree(aifactoryObj); aiFactories.Add(newAiFactorySeqObj); KismetHelper.AddObjectToSequence(newAiFactorySeqObj, flySeq, false); // Update the backing factory object var backingFactory = newAiFactorySeqObj.GetProperty <ObjectProperty>("Factory").ResolveToEntry(package) as ExportEntry; backingFactory.WriteProperty(new ObjectProperty(package.FindExport(randPawn.ChallengeTypeFullPath), "ActorType")); var collection = backingFactory.GetProperty <ArrayProperty <ObjectProperty> >("ActorResourceCollection"); collection.Clear(); foreach (var asset in randPawn.AssetPaths) { collection.Add(new ObjectProperty(package.FindExport(asset))); } backingFactory.WriteProperty(collection); } } if (newPawnsInThisSeq.Any()) { // install the switch var randSw = MERSeqTools.InstallRandomSwitchIntoSequence(flySeq, numEnemies); outbound[0][0].LinkedOp = randSw; SeqTools.WriteOutboundLinksToNode(preGate, outbound); // Hook up switch to ai factories for (int i = 0; i < numEnemies; i++) { var linkDesc = $"Link {i + 1}"; KismetHelper.CreateOutputLink(randSw, linkDesc, aiFactories[i]); // switches are indexed at 1 } } } } }
/// <summary> /// Ports a power into a package /// </summary> /// <param name="targetPackage"></param> /// <param name="powerInfo"></param> /// <param name="additionalPowers">A list of additioanl powers that are referenced when this powerinfo is an import only power (prevent re-opening package)</param> /// <returns></returns> public static IEntry PortPowerIntoPackage(IMEPackage targetPackage, PowerInfo powerInfo, out IMEPackage sourcePackage) { if (powerInfo.IsCorrectedPackage) { var sourceData = MERUtilities.GetEmbeddedStaticFilesBinaryFile("correctedloadouts.powers." + powerInfo.PackageFileName); sourcePackage = MEPackageHandler.OpenMEPackageFromStream(new MemoryStream(sourceData)); } else { sourcePackage = NonSharedPackageCache.Cache.GetCachedPackage(powerInfo.PackageFileName); } if (sourcePackage != null) { var sourceExport = sourcePackage.GetUExport(powerInfo.SourceUIndex); if (!sourceExport.InheritsFrom("SFXPower") || sourceExport.IsDefaultObject) { throw new Exception("Wrong setup!"); } if (sourceExport.Parent != null && sourceExport.Parent.ClassName != "Package") { throw new Exception("Cannot port power - parent object is not Package!"); } var newParent = EntryExporter.PortParents(sourceExport, targetPackage); IEntry newEntry; if (powerInfo.ImportOnly) { //Debug.WriteLine($"ImportOnly in file {targetPackage.FilePath}"); if (powerInfo.RequiresStartupPackage) { ThreadSafeDLCStartupPackage.AddStartupPackage(Path.GetFileNameWithoutExtension(powerInfo.PackageFileName)); if (powerInfo.IsCorrectedPackage) { // File must be added to MERFS DLC var outP = Path.Combine(MERFileSystem.DLCModCookedPath, powerInfo.PackageFileName); if (!File.Exists(outP)) { sourcePackage.Save(outP, true); } } } newEntry = PackageTools.CreateImportForClass(sourceExport, targetPackage, newParent); // Port in extra imports so the calling class can reference them as necessary. foreach (var addlPow in powerInfo.AdditionalRequiredPowers) { var addlSourceExp = sourcePackage.FindExport(addlPow); PackageTools.CreateImportForClass(addlSourceExp, targetPackage, EntryExporter.PortParents(addlSourceExp, targetPackage)); } } else { #if DEBUG // DEBUG ONLY----------------------------------- //var defaults = sourceExport.GetDefaults(); //defaults.RemoveProperty("VFX"); //var vfx = defaults.GetProperty<ObjectProperty>("VFX").ResolveToEntry(sourcePackage) as ExportEntry; //vxx.RemoveProperty("PlayerCrust"); //vfx.FileRef.GetUExport(1544).RemoveProperty("oPrefab"); ////vfx = defaults.FileRef.GetUExport(6211); // Prefab ////vfx.RemoveProperty("WorldImpactVisualEffect"); //MERPackageCache cached = new MERPackageCache(); //EntryExporter.ExportExportToPackage(vfx, targetPackage, out newEntry, cached); //PackageTools.AddReferencesToWorld(targetPackage, new [] {newEntry as ExportEntry}); //return null; // END DEBUG ONLY-------------------------------- #endif List <EntryStringPair> relinkResults = null; if ((powerInfo.IsCorrectedPackage || (PackageTools.IsPersistentPackage(powerInfo.PackageFileName) && MERFileSystem.GetPackageFile(powerInfo.PackageFileName.ToLocalizedFilename()) == null))) { // Faster this way, without having to check imports Dictionary <IEntry, IEntry> crossPCCObjectMap = new Dictionary <IEntry, IEntry>(); // Not sure what this is used for these days. SHould probably just be part of the method relinkResults = EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, sourceExport, targetPackage, newParent, true, out newEntry, crossPCCObjectMap); } else { // MEMORY SAFE (resolve imports to exports) MERPackageCache cache = new MERPackageCache(); relinkResults = EntryExporter.ExportExportToPackage(sourceExport, targetPackage, out newEntry, cache); } if (relinkResults.Any()) { Debugger.Break(); } } return(newEntry); } return(null); // No package was found }
public void CreateLiveEditFile() { string filePath = LiveFaceFxEditorFilePath; File.Copy(Path.Combine(App.ExecFolder, "ME3EmptyLevel.pcc"), filePath); LiveFile = MEPackageHandler.OpenMEPackage(filePath); for (int i = 0; i < LiveFile.Names.Count; i++) { if (LiveFile.Names[i].Equals("ME3EmptyLevel")) { LiveFile.replaceName(i, Path.GetFileNameWithoutExtension(filePath)); } } var packguid = Guid.NewGuid(); var package = LiveFile.GetUExport(1); package.PackageGUID = packguid; LiveFile.PackageGuid = packguid; EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, SourceAnimSet.Export.Parent, LiveFile, null, true, out _); var gender = SourceAnimSet.Export.ObjectNameString.Last() switch { 'F' => FaceFXGender.Female, 'M' => FaceFXGender.Male, _ => FaceFXGender.NonSpkr }; ActorTag = null; try { if (gender is not FaceFXGender.NonSpkr) { bool isFemale = gender is FaceFXGender.Female; var bioConv = LiveFile.Exports.First(exp => exp.Class.ObjectName == "BioConversation"); var LiveFileAnimSet = LiveFile.FindExport(SourceAnimSet.Export.InstancedFullPath); var propName = isFemale ? "m_aMaleFaceSets" : "m_aFemaleFaceSets"; int idx = bioConv.GetProperty <ArrayProperty <ObjectProperty> >(propName).FindIndex(objProp => objProp.Value == LiveFileAnimSet.UIndex); if (idx is 0) { //player ActorTag = $"Player_{(isFemale ? 'F' : 'M')}"; IEntry ent; using (IMEPackage soldierFile = MEPackageHandler.OpenME3Package(Path.Combine(ME3Directory.CookedPCPath, "SFXCharacterClass_Soldier.pcc"))) { EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, soldierFile.GetUExport(isFemale ? 10327 : 10330), LiveFile, LiveFile.GetUExport(3), true, out ent); } ExportEntry actor = (ExportEntry)ent; LiveFile.AddToLevelActorsIfNotThere(actor); actor.WriteProperty(new NameProperty(ActorTag, "Tag")); using (IMEPackage clothingFile = MEPackageHandler.OpenME3Package(Path.Combine(ME3Directory.CookedPCPath, $"BIOG_HM{(isFemale ? "F" : "M")}_ARM_CTH_R.pcc"))) { var clothingPackage = EntryImporter.GetOrAddCrossImportOrPackage("CTHa", clothingFile, LiveFile); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, clothingFile.GetUExport(isFemale ? 1625 : 1966), LiveFile, clothingPackage, true, out ent); } ExportEntry bodyComponent = LiveFile.GetUExport(actor.GetProperty <ObjectProperty>("BodyMesh").Value); bodyComponent.WriteProperty(new ObjectProperty(ent.UIndex, "SkeletalMesh")); } else if (idx is 1) { //owner using IMEPackage parentFile = getParentFile(); foreach (ExportEntry export in parentFile.Exports.Where(exp => exp.ClassName is "SFXSeqAct_StartConversation" or "SFXSeqAct_StartAmbientConv")) { if (export.GetProperty <ObjectProperty>("Conv") is ObjectProperty convProp && parentFile.TryGetImport(convProp.Value, out var convImport) && convImport.ObjectName == bioConv.ObjectName) { ExportEntry seqVar = parentFile.GetUExport(export.GetProperty <ArrayProperty <StructProperty> >("VariableLinks")[0].GetProp <ArrayProperty <ObjectProperty> >("LinkedVariables")[0].Value); if (seqVar.ClassName == "BioSeqVar_ObjectFindByTag") { ActorTag = seqVar.GetProperty <NameProperty>("m_sObjectTagToFind").Value; if (!ActorTag.StartsWith("hench_", StringComparison.OrdinalIgnoreCase)) { importTaggedActor(parentFile); } } else { EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, parentFile.GetUExport(seqVar.GetProperty <ObjectProperty>("ObjValue").Value), LiveFile, LiveFile.GetUExport(3), true, out var ent); ExportEntry actor = (ExportEntry)ent; LiveFile.AddToLevelActorsIfNotThere(actor); ActorTag = actor.GetProperty <NameProperty>("Tag")?.Value.Name; if (ActorTag is null) { ActorTag = "ConvoOwner"; actor.WriteProperty(new NameProperty(ActorTag, "Tag")); } } break; } } } else { ActorTag = bioConv.GetProperty <ArrayProperty <NameProperty> >("m_aSpeakerList")[idx - 2].Value; if (!ActorTag.StartsWith("hench_", StringComparison.OrdinalIgnoreCase)) { using IMEPackage parentFile = getParentFile(); importTaggedActor(parentFile); } } } else { //find nonspkr linkage somehow } }
public static void RunGame2EmailMerge(GameTarget target) { M3MergeDLC.RemoveMergeDLC(target); var loadedFiles = MELoadedFiles.GetFilesLoadedInGame(target.Game, gameRootOverride: target.TargetPath); // File to base modifications on using IMEPackage pcc = MEPackageHandler.OpenMEPackage(loadedFiles[@"BioD_Nor103_Messages.pcc"]); // Path to Message templates file - different files for ME2/LE2 string ResourcesFilePath = $@"MassEffectModManagerCore.modmanager.emailmerge.{target.Game}.103Message_Template_{target.Game}"; using IMEPackage resources = MEPackageHandler.OpenMEPackageFromStream(Utilities.GetResourceStream(ResourcesFilePath)); // Startup file to place conditionals and transitions into using IMEPackage startup = MEPackageHandler.OpenMEPackageFromStream(Utilities.GetResourceStream( $@"MassEffectModManagerCore.modmanager.mergedlc.{target.Game}.Startup_{M3MergeDLC.MERGE_DLC_FOLDERNAME}.pcc")); var emailInfos = new List <ME2EmailMergeFile>(); var jsonSupercedances = M3Directories.GetFileSupercedances(target, new[] { @".json" }); if (jsonSupercedances.TryGetValue(EMAIL_MERGE_MANIFEST_FILE, out var jsonList)) { jsonList.Reverse(); foreach (var dlc in jsonList) { var jsonFile = Path.Combine(M3Directories.GetDLCPath(target), dlc, target.Game.CookedDirName(), EMAIL_MERGE_MANIFEST_FILE); emailInfos.Add(JsonConvert.DeserializeObject <ME2EmailMergeFile>(File.ReadAllText(jsonFile))); } } // Sanity checks if (!emailInfos.Any() || !emailInfos.SelectMany(e => e.Emails).Any()) { return; } if (emailInfos.Any(e => e.Game != target.Game)) { throw new Exception("ME2 email merge manifest targets incorrect game"); } // Startup File // Could replace this with full instanced path in M3 implementation ExportEntry stateEventMapExport = startup.Exports .First(e => e.ClassName == "BioStateEventMap" && e.ObjectName == "StateTransitionMap"); BioStateEventMap StateEventMap = stateEventMapExport.GetBinaryData <BioStateEventMap>(); ExportEntry ConditionalClass = startup.FindExport($@"PlotManager{M3MergeDLC.MERGE_DLC_FOLDERNAME}.BioAutoConditionals"); #region Sequence Exports // Send message - All email conditionals are checked and emails transitions are triggered ExportEntry SendMessageContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Send_Messages"); ExportEntry LastSendMessage = KismetHelper.GetSequenceObjects(SendMessageContainer).OfType <ExportEntry>() .FirstOrDefault(e => { var outbound = KismetHelper.GetOutboundLinksOfNode(e); return(outbound.Count == 1 && outbound[0].Count == 0); }); ExportEntry TemplateSendMessage = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Send_MessageTemplate"); ExportEntry TemplateSendMessageBoolCheck = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Send_MessageTemplate_BoolCheck"); // Mark Read - email ints are set to read // This is the only section that does not gracefully handle different DLC installations - DLC_CER is required atm ExportEntry MarkReadContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_Read"); ExportEntry LastMarkRead = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_Read.DLC_CER"); ExportEntry MarkReadOutLink = KismetHelper.GetOutboundLinksOfNode(LastMarkRead)[0][0].LinkedOp as ExportEntry; KismetHelper.RemoveOutputLinks(LastMarkRead); ExportEntry TemplateMarkRead = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_ReadTemplate"); ExportEntry TemplateMarkReadTransition = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Mark_Read_Transition"); // Display Messages - Str refs are passed through to GUI ExportEntry DisplayMessageContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Display_Messages"); ExportEntry DisplayMessageOutLink = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Display_Messages.SeqCond_CompareBool_0"); ExportEntry LastDisplayMessage = SeqTools.FindOutboundConnectionsToNode(DisplayMessageOutLink, KismetHelper.GetSequenceObjects(DisplayMessageContainer).OfType <ExportEntry>())[0]; KismetHelper.RemoveOutputLinks(LastDisplayMessage); var DisplayMessageVariableLinks = LastDisplayMessage.GetProperty <ArrayProperty <StructProperty> >("VariableLinks"); ExportEntry TemplateDisplayMessage = resources.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Display_MessageTemplate"); // Archive Messages - Message ints are set to 3 ExportEntry ArchiveContainer = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Archive_Message"); ExportEntry ArchiveSwitch = pcc.FindExport(@"TheWorld.PersistentLevel.Main_Sequence.Archive_Message.SeqAct_Switch_0"); ExportEntry ArchiveOutLink = pcc.FindExport( @"TheWorld.PersistentLevel.Main_Sequence.Archive_Message.BioSeqAct_PMCheckConditional_1"); ExportEntry ExampleSetInt = KismetHelper.GetOutboundLinksOfNode(ArchiveSwitch)[0][0].LinkedOp as ExportEntry; ExportEntry ExamplePlotInt = SeqTools.GetVariableLinksOfNode(ExampleSetInt)[0].LinkedNodes[0] as ExportEntry; #endregion int messageID = KismetHelper.GetOutboundLinksOfNode(ArchiveSwitch).Count + 1; int currentSwCount = ArchiveSwitch.GetProperty <IntProperty>("LinkCount").Value; foreach (var emailMod in emailInfos) { string modName = "DLC_MOD_" + emailMod.ModName; foreach (var email in emailMod.Emails) { string emailName = modName + "_" + email.EmailName; // Create send transition int transitionId = WriteTransition(StateEventMap, email.StatusPlotInt); int conditionalId = WriteConditional(email.TriggerConditional); #region SendMessage ////////////// // SendMessage ////////////// // Create seq object var SMTemp = emailMod.InMemoryBool.HasValue ? TemplateSendMessageBoolCheck : TemplateSendMessage; EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, SMTemp, pcc, SendMessageContainer, true, new RelinkerOptionsPackage(), out var outSendEntry); var newSend = outSendEntry as ExportEntry; // Set name, comment, add to sequence newSend.ObjectName = new NameReference(emailName); KismetHelper.AddObjectToSequence(newSend, SendMessageContainer); KismetHelper.SetComment(newSend, emailName); if (target.Game == MEGame.ME2) { newSend.WriteProperty(new StrProperty(emailName, "ObjName")); } // Set Trigger Conditional var pmCheckConditionalSM = newSend.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMCheckConditional" && e is ExportEntry); if (pmCheckConditionalSM is ExportEntry conditional) { conditional.WriteProperty(new IntProperty(conditionalId, "m_nIndex")); KismetHelper.SetComment(conditional, "Time for " + email.EmailName + "?"); } // Set Send Transition var pmExecuteTransitionSM = newSend.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMExecuteTransition" && e is ExportEntry); if (pmExecuteTransitionSM is ExportEntry transition) { transition.WriteProperty(new IntProperty(transitionId, "m_nIndex")); KismetHelper.SetComment(transition, "Send " + email.EmailName + " message."); } // Set Send Transition if (emailMod.InMemoryBool.HasValue) { var pmCheckStateSM = newSend.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMCheckState" && e is ExportEntry); if (pmCheckStateSM is ExportEntry checkState) { checkState.WriteProperty(new IntProperty(emailMod.InMemoryBool.Value, "m_nIndex")); KismetHelper.SetComment(checkState, "Is " + emailMod.ModName + " installed?"); } } // Hook up output links KismetHelper.CreateOutputLink(LastSendMessage, "Out", newSend); LastSendMessage = newSend; #endregion #region MarkRead /////////// // MarkRead /////////// // Create seq object var MRTemp = email.ReadTransition.HasValue ? TemplateMarkReadTransition : TemplateMarkRead; EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, MRTemp, pcc, MarkReadContainer, true, new RelinkerOptionsPackage(), out var outMarkReadEntry); var newMarkRead = outMarkReadEntry as ExportEntry; // Set name, comment, add to sequence newMarkRead.ObjectName = new NameReference(emailName); KismetHelper.AddObjectToSequence(newMarkRead, MarkReadContainer); KismetHelper.SetComment(newMarkRead, emailName); if (target.Game == MEGame.ME2) { newMarkRead.WriteProperty(new StrProperty(emailName, "ObjName")); } // Set Plot Int var storyManagerIntMR = newMarkRead.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqVar_StoryManagerInt" && e is ExportEntry); if (storyManagerIntMR is ExportEntry plotIntMR) { plotIntMR.WriteProperty(new IntProperty(email.StatusPlotInt, "m_nIndex")); KismetHelper.SetComment(plotIntMR, email.EmailName); } if (email.ReadTransition.HasValue) { var pmExecuteTransitionMR = newMarkRead.GetChildren() .FirstOrDefault(e => e.ClassName == "BioSeqAct_PMExecuteTransition" && e is ExportEntry); if (pmExecuteTransitionMR is ExportEntry transitionMR) { transitionMR.WriteProperty(new IntProperty(email.ReadTransition.Value, "m_nIndex")); KismetHelper.SetComment(transitionMR, "Trigger " + email.EmailName + " read transition"); } } // Hook up output links KismetHelper.CreateOutputLink(LastMarkRead, "Out", newMarkRead); LastMarkRead = newMarkRead; #endregion #region DisplayEmail //////////////// // Display Email //////////////// // Create seq object EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, TemplateDisplayMessage, pcc, DisplayMessageContainer, true, new RelinkerOptionsPackage(), out var outDisplayMessage); var newDisplayMessage = outDisplayMessage as ExportEntry; // Set name, comment, variable links, add to sequence newDisplayMessage.ObjectName = new NameReference(emailName); KismetHelper.AddObjectToSequence(newDisplayMessage, DisplayMessageContainer); newDisplayMessage.WriteProperty(DisplayMessageVariableLinks); KismetHelper.SetComment(newDisplayMessage, emailName); if (target.Game == MEGame.ME2) { newDisplayMessage.WriteProperty(new StrProperty(emailName, "ObjName")); } var displayChildren = newDisplayMessage.GetChildren(); // Set Plot Int var storyManagerIntDE = displayChildren.FirstOrDefault(e => e.ClassName == "BioSeqVar_StoryManagerInt" && e is ExportEntry); if (storyManagerIntDE is ExportEntry plotIntDE) { plotIntDE.WriteProperty(new IntProperty(email.StatusPlotInt, "m_nIndex")); } // Set Email ID var emailIdDE = displayChildren.FirstOrDefault(e => e.ClassName == "SeqVar_Int" && e is ExportEntry); if (emailIdDE is ExportEntry EmailIDDE) { EmailIDDE.WriteProperty(new IntProperty(messageID, "IntValue")); } // Set Title StrRef var titleStrRef = displayChildren.FirstOrDefault(e => e.ClassName == "BioSeqVar_StrRef" && e is ExportEntry ee && ee.GetProperty <NameProperty>("VarName").Value == "Title StrRef"); if (titleStrRef is ExportEntry Title) { Title.WriteProperty(new StringRefProperty(email.TitleStrRef, "m_srValue")); } // Set Description StrRef var descStrRef = displayChildren.FirstOrDefault(e => e.ClassName == "BioSeqVar_StrRef" && e is ExportEntry ee && ee.GetProperty <NameProperty>("VarName").Value == "Desc StrRef"); if (descStrRef is ExportEntry Desc) { Desc.WriteProperty(new StringRefProperty(email.DescStrRef, "m_srValue")); } // Hook up output links KismetHelper.CreateOutputLink(LastDisplayMessage, "Out", newDisplayMessage); LastDisplayMessage = newDisplayMessage; #endregion #region ArchiveEmail //////////////// // Archive Email //////////////// var NewSetInt = EntryCloner.CloneEntry(ExampleSetInt); KismetHelper.AddObjectToSequence(NewSetInt, ArchiveContainer); KismetHelper.CreateOutputLink(NewSetInt, "Out", ArchiveOutLink); KismetHelper.CreateNewOutputLink(ArchiveSwitch, "Link " + (messageID - 1), NewSetInt); var NewPlotInt = EntryCloner.CloneEntry(ExamplePlotInt); KismetHelper.AddObjectToSequence(NewPlotInt, ArchiveContainer); NewPlotInt.WriteProperty(new IntProperty(email.StatusPlotInt, "m_nIndex")); NewPlotInt.WriteProperty(new StrProperty(emailName, "m_sRefName")); var linkedVars = SeqTools.GetVariableLinksOfNode(NewSetInt); linkedVars[0].LinkedNodes = new List <IEntry>() { NewPlotInt }; SeqTools.WriteVariableLinksToNode(NewSetInt, linkedVars); messageID++; currentSwCount++; #endregion } } KismetHelper.CreateOutputLink(LastMarkRead, "Out", MarkReadOutLink); KismetHelper.CreateOutputLink(LastDisplayMessage, "Out", DisplayMessageOutLink); ArchiveSwitch.WriteProperty(new IntProperty(currentSwCount, "LinkCount")); stateEventMapExport.WriteBinary(StateEventMap); // Save Messages file into DLC var cookedDir = Path.Combine(M3Directories.GetDLCPath(target), M3MergeDLC.MERGE_DLC_FOLDERNAME, target.Game.CookedDirName()); var outMessages = Path.Combine(cookedDir, @"BioD_Nor103_Messages.pcc"); pcc.Save(outMessages); // Save Startup file into DLC var startupF = Path.Combine(cookedDir, $@"Startup_{M3MergeDLC.MERGE_DLC_FOLDERNAME}.pcc"); startup.Save(startupF); }
public static bool PortPawnIntoPackage(PortablePawn pawn, IMEPackage targetPackage) { if (IsPawnAssetInPackageAlready(pawn, targetPackage)) { return(true); // Pawn asset to port in already ported in } IMEPackage pawnPackage = null; if (pawn.IsCorrectedPackage) { // DEBUG //if (pawn.PackageFilename == "BioPawn_Collector_Batarian.pcc") //{ // pawnPackage = MEPackageHandler.OpenMEPackage(@"C:\Users\mgame\source\repos\ME2Randomizer\ME2Randomizer\staticfiles\binary\correctedpawns\" + pawn.PackageFilename); //} //else //{ var correctedPawnData = MERUtilities.GetEmbeddedStaticFilesBinaryFile($"correctedpawns.{pawn.PackageFilename}"); pawnPackage = MEPackageHandler.OpenMEPackageFromStream(new MemoryStream(correctedPawnData)); //} } else { var pF = MERFileSystem.GetPackageFile(pawn.PackageFilename); if (pF != null) { pawnPackage = MERFileSystem.OpenMEPackage(pF); } else { Debug.WriteLine("Pawn package not found: {pawn.PackageFilename}"); } } if (pawnPackage != null) { PackageTools.PortExportIntoPackage(targetPackage, pawnPackage.FindExport(pawn.AssetToPortIn), useMemorySafeImport: !pawn.IsCorrectedPackage); // Ensure the assets are too as they may not be directly referenced except in the level instance foreach (var asset in pawn.AssetPaths) { if (targetPackage.FindExport(asset) == null) { PackageTools.PortExportIntoPackage(targetPackage, pawnPackage.FindExport(asset), useMemorySafeImport: !pawn.IsCorrectedPackage); } } if (pawn.TextureUpdates != null) { foreach (var tu in pawn.TextureUpdates) { var targetTextureExp = targetPackage.FindExport(tu.TextureInstancedFullPath); TFCBuilder.InstallTexture(tu, targetTextureExp); } } return(true); } return(false); }
public static bool IsPawnAssetInPackageAlready(PortablePawn pawn, IMEPackage targetPackage) { return(targetPackage.FindExport(pawn.AssetToPortIn) != null); }
/// <summary> /// Ports an export into a package. Checks if the export already exists, and if it does, returns that instead. /// </summary> /// <param name="targetPackage">The target package to port into.</param> /// <param name="sourceExport">The source export to port over, including all dependencies and references.</param> /// <param name="targetLink">The target link UIndex. Only used if createParentPackages is false.</param> /// <param name="createParentPackages">If the export should be ported in the same way as it was cooked into the package natively, e.g. create the parent package paths. The export must directly sit under a Package or an exception will be thrown.</param> /// <param name="ensureMemoryUniqueness">If this object is an instance, such as a sequence object, and should be made memory-unique so it is properly used</param> /// <returns></returns> public static ExportEntry PortExportIntoPackage(IMEPackage targetPackage, ExportEntry sourceExport, int targetLink = 0, bool createParentPackages = true, bool ensureMemoryUniqueness = false, bool useMemorySafeImport = false, PackageCache cache = null) { #if DEBUG // in preprocessor to prevent this from running in release mode if (sourceExport.FileRef.FilePath != null && targetPackage.FilePath != null) { Debug.WriteLine($"Porting {sourceExport.InstancedFullPath} from {Path.GetFileName(sourceExport.FileRef.FilePath)} into {Path.GetFileName(targetPackage.FilePath)}"); } #endif var existing = targetPackage.FindExport(sourceExport.InstancedFullPath); if (existing != null) { return(existing); } // Create parent hierarchy IEntry newParent = null; if (createParentPackages) { List <IEntry> parents = new List <IEntry>(); var parent = sourceExport.Parent; while (parent != null) { if (parent.ClassName != "Package") { throw new Exception("Parent is not package!"); } parents.Add(parent); parent = parent.Parent; } // Create the parents parents.Reverse(); foreach (var p in parents) { var sourceFullPath = p.InstancedFullPath; var matchingParent = targetPackage.FindEntry(sourceFullPath); if (matchingParent != null) { newParent = matchingParent; continue; } newParent = ExportCreator.CreatePackageExport(targetPackage, p.ObjectName, newParent); } } else { newParent = targetPackage.GetEntry(targetLink); } IEntry newEntry; if (!useMemorySafeImport) { Dictionary <IEntry, IEntry> crossPCCObjectMap = new Dictionary <IEntry, IEntry>(); // Not sure what this is used for these days. Should probably just be part of the method var relinkResults = EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneAllDependencies, sourceExport, targetPackage, newParent, true, out newEntry, crossPCCObjectMap); if (relinkResults.Any()) { Debugger.Break(); } } else { // Memory safe, fixes upstream var relinkedResults = EntryExporter.ExportExportToPackage(sourceExport, targetPackage, out newEntry, MERFileSystem.GetGlobalCache(), cache); if (relinkedResults.Any()) { Debugger.Break(); } } #if DEBUG //(sourceExport.FileRef as MEPackage).CompareToPackageDetailed(targetPackage); #endif // Helps ensure we don't have memory duplicates if (ensureMemoryUniqueness) { newEntry.ObjectName = targetPackage.GetNextIndexedName(newEntry.ObjectName); } return(newEntry as ExportEntry); }