/// <summary> /// Installs the specified r2d to the specified export. Specify an asset name if you wish to use a specific asset in the RTexture2D object. /// </summary> /// <param name="r2d"></param> /// <param name="export"></param> /// <param name="asset"></param> public static void InstallTexture(RTexture2D r2d, ExportEntry export, string asset = null) { // If no asset was specified pick a random asset asset ??= r2d.FetchRandomTextureAsset(); // 2. Is this asset already parsed? if (r2d.InstantiatedItems.TryGetValue(asset, out var instantiated)) { // It's already been instantiated. Just use this data instead MERLog.Information($@"Writing out cached asset {asset} for {export.InstancedFullPath}"); export.WritePropertiesAndBinary(instantiated.props, instantiated.texData); } else { MERLog.Information($@"Installing texture asset {asset} for {export.InstancedFullPath}"); // 3. Asset has not been setup yet. Write out the precomputed data. export.WriteBinary(GetTextureAssetBinary(asset)); // 4. Read in the data so it's in the correct context. var ut2d = ObjectBinary.From <UTexture2D>(export); // 5. Move compressed mips to TFC foreach (var mip in ut2d.Mips) { if (mip.IsCompressed) { mip.DataOffset = TFCBuilder.WriteMip(r2d, mip.Mip); // If it's compressed it needs to be stored externally. if (mip.StorageType == StorageTypes.pccLZO) { mip.StorageType = StorageTypes.extLZO; } if (mip.StorageType == StorageTypes.pccZlib) { mip.StorageType = StorageTypes.extZlib; } } } // 6. Setup the properties var props = export.GetProperties(); props.AddOrReplaceProp(new IntProperty(ut2d.Mips.Count - 1, @"MipTailBaseIdx")); props.AddOrReplaceProp(new IntProperty(ut2d.Mips[0].SizeX, @"SizeX")); props.AddOrReplaceProp(new IntProperty(ut2d.Mips[0].SizeY, @"SizeY")); props.AddOrReplaceProp(r2d.PreMountTexture ? ActiveBuilder.BGTFCNameProp : ActiveBuilder.DLCTFCNameProp); props.AddOrReplaceProp(r2d.PreMountTexture ? ActiveBuilder.BGTFCGuidProp : ActiveBuilder.DLCTFCGuidProp); if (r2d.LODGroup != null) { // Write a new LOD property props.AddOrReplaceProp(r2d.LODGroup); } // 7. Commit the export export.WritePropertiesAndBinary(props, ut2d); // 8. Cache the work that's been done so we don't need to it again. r2d.InstantiatedItems[asset] = (props, ut2d); } }
public static void SetCollectionActorLocation(ExportEntry component, float x, float y, float z, List <ExportEntry> collectionitems = null, ExportEntry collectionactor = null) { if (collectionactor == null) { if (!(component.HasParent && component.Parent.ClassName.Contains("CollectionActor"))) { return; } collectionactor = (ExportEntry)component.Parent; } collectionitems ??= GetCollectionItems(collectionactor); if (collectionitems?.Count > 0) { var idx = collectionitems.FindIndex(o => o != null && o.UIndex == component.UIndex); if (idx >= 0) { var binData = (StaticCollectionActor)ObjectBinary.From(collectionactor); Matrix m = binData.LocalToWorldTransforms[idx]; m.TranslationVector = new Vector3(x, y, z); binData.LocalToWorldTransforms[idx] = m; collectionactor.WriteBinary(binData); } } }
//private static bool CanRandomize(ExportEntry export) => !export.IsDefaultObject && export.ClassName == @"TextureMovie" && ExportNameToAssetMapping.ContainsKey(export.ObjectName.Name); //public static bool RandomizeExport(ExportEntry export, RandomizationOption option) //{ // if (!CanRandomize(export)) return false; // var assets = ExportNameToAssetMapping[export.ObjectName.Name]; // byte[] tmAsset = GetTextureMovieAssetBinary(assets[ThreadSafeRandom.Next(assets.Count)]); // var tm = ObjectBinary.From<TextureMovie>(export); // tm.EmbeddedData = tmAsset; // tm.DataSize = tmAsset.Length; // export.WriteBinary(tm); // return true; //} // ME2 only has few texture movies so these are used public static bool RandomizeExportDirect(ExportEntry export, RandomizationOption option, byte[] tmAsset) { var tm = ObjectBinary.From <TextureMovie>(export); tm.EmbeddedData = tmAsset; tm.DataSize = tmAsset.Length; export.WriteBinary(tm); return(true); }
private static void InstallDynamicAnimSetRefForSkeletalMesh(ExportEntry export, RBioEvtSysTrackGesture.Gesture gesture) { // We have parent sequence data var skmDynamicAnimSets = export.GetProperty <ArrayProperty <ObjectProperty> >("AnimSets") ?? new ArrayProperty <ObjectProperty>("AnimSets"); // Check to see if there is any item that uses our bioanimset var bioAnimSet = gesture.GetBioAnimSet(export.FileRef); if (bioAnimSet != null) { ExportEntry skmBioDynamicAnimSet = null; foreach (var skmDynAnimSet in skmDynamicAnimSets) { var kEntry = skmDynAnimSet.ResolveToEntry(export.FileRef) as ExportEntry; // I don't think these can be imports as they're part of the seq var associatedset = kEntry.GetProperty <ObjectProperty>("m_pBioAnimSetData").ResolveToEntry(export.FileRef); if (associatedset == bioAnimSet) { // It's this one skmBioDynamicAnimSet = kEntry; break; } } if (skmBioDynamicAnimSet == null) { // We need to generate a new one PropertyCollection props = new PropertyCollection(); props.Add(new NameProperty(gesture.GestureSet, "m_nmOrigSetName")); props.Add(new ArrayProperty <ObjectProperty>("Sequences")); props.Add(new ObjectProperty(bioAnimSet, "m_pBioAnimSetData")); skmBioDynamicAnimSet = ExportCreator.CreateExport(export.FileRef, $"BioDynamicAnimSet", "BioDynamicAnimSet", export); // Write a blank count of 0 - we will update this in subsequent call // This must be here to ensure parser can read it skmBioDynamicAnimSet.WritePropertiesAndBinary(props, new byte[4]); skmDynamicAnimSets.Add(new ObjectProperty(skmBioDynamicAnimSet)); // Add new export to sequence's list of biodynamicanimsets export.WriteProperty(skmDynamicAnimSets); } var currentObjs = skmBioDynamicAnimSet.GetProperty <ArrayProperty <ObjectProperty> >("Sequences"); if (currentObjs.All(x => x.Value != gesture.Entry.UIndex)) { // We need to add our item to it currentObjs.Add(new ObjectProperty(gesture.Entry)); var bin = ObjectBinary.From <BioDynamicAnimSet>(skmBioDynamicAnimSet); bin.SequenceNamesToUnkMap[gesture.GestureAnim] = 1; // Not sure what the value should be, or if game actually reads this // FIX IT IF WE EVER FIGURE IT OUT! skmBioDynamicAnimSet.WriteProperty(currentObjs); skmBioDynamicAnimSet.WriteBinary(bin); } } }
private void DisableConfigFlag(IMEPackage package, ExportEntry export, Mod installingMod) { if (ObjectBinary.From(export) is UProperty ob) { Log.Information($@"Disabling config flag on {export.InstancedFullPath}"); ob.PropertyFlags &= ~UnrealFlags.EPropertyFlags.Config; export.WriteBinary(ob); } else { throw new Exception(M3L.GetString(M3L.string_interp_mergefile_notPropertyExportConfigFlag, export.InstancedFullPath, package.FilePath)); } }
private static void TestR(ExportEntry export) { if (/*export.UIndex == 36224 && */ export.ClassName == "Material") { var obj = ObjectBinary.From <Material>(export); foreach (var v in obj.SM3MaterialResource.UniformPixelVectorExpressions) { if (v is MaterialUniformExpressionVectorParameter vp) { vp.DefaultA = ThreadSafeRandom.NextFloat(0, 1); vp.DefaultR = ThreadSafeRandom.NextFloat(); vp.DefaultG = ThreadSafeRandom.NextFloat(); vp.DefaultB = ThreadSafeRandom.NextFloat(); } else if (v is MaterialUniformExpressionAppendVector av) { } } foreach (var v in obj.SM3MaterialResource.UniformPixelVectorExpressions) { } export.WriteBinary(obj); } if (export.UIndex == 37354 || export.UIndex == 37355) { var vParms = VectorParameter.GetVectorParameters(export); if (vParms != null) { foreach (var vParm in vParms) { CFVector4 nv = new CFVector4(); nv.W = ThreadSafeRandom.NextFloat(2000); nv.X = ThreadSafeRandom.NextFloat(2000); nv.Y = ThreadSafeRandom.NextFloat(2000); nv.Z = ThreadSafeRandom.NextFloat(2000); vParm.ParameterValue = nv; } } } }
public static bool RandomizeExport(ExportEntry exp, RandomizationOption option) { if (!CanRandomize(exp, out var shiftDirection, out var min, out var max)) { return(false); } var shiftAmt = ThreadSafeRandom.NextFloat(min, max); var morphTarget = ObjectBinary.From <MorphTarget>(exp); foreach (var lm in morphTarget.MorphLODModels) { foreach (var v in lm.Vertices) { var posDelta = v.PositionDelta; if (shiftDirection == 0) // IN OUT //posDelta.X += shiftAmt; { posDelta.X *= shiftAmt; } if (shiftDirection == 1) // LEFT RIGHT //posDelta.Y += shiftAmt; { posDelta.Y *= shiftAmt; } if (shiftDirection == 2) // UP DOWN //posDelta.Z += shiftAmt; { posDelta.Z *= shiftAmt; } v.PositionDelta = posDelta; // Require reassignment } } exp.WriteBinary(morphTarget); return(true); }
public static SkeletalMesh FuzzSkeleton(ExportEntry export, RandomizationOption option) { // Goofs up the RefSkeleton values var objBin = ObjectBinary.From <SkeletalMesh>(export); foreach (var bone in objBin.RefSkeleton) { if (!bone.Name.Name.Contains("eye", StringComparison.InvariantCultureIgnoreCase) && !bone.Name.Name.Contains("sneer", StringComparison.InvariantCultureIgnoreCase) && !bone.Name.Name.Contains("nose", StringComparison.InvariantCultureIgnoreCase) && !bone.Name.Name.Contains("brow", StringComparison.InvariantCultureIgnoreCase) && !bone.Name.Name.Contains("jaw", StringComparison.InvariantCultureIgnoreCase)) { continue; } var v3 = bone.Position; v3.X *= ThreadSafeRandom.NextFloat(1 - (option.SliderValue / 2), 1 + option.SliderValue); v3.Y *= ThreadSafeRandom.NextFloat(1 - (option.SliderValue / 2), 1 + option.SliderValue); v3.Z *= ThreadSafeRandom.NextFloat(1 - (option.SliderValue / 2), 1 + option.SliderValue); bone.Position = v3; } export.WriteBinary(objBin); return(objBin); }
public void serializeTalkfileToExport(ExportEntry export, bool savePackage = false) { /* converts Huffmann Tree to binary form */ byte[] treeBuffer = ConvertHuffmanTreeToBuffer(); var encodedStrings = new List <EncodedString>(); int i = 0; foreach (var entry in _inputData) { if (entry.Flags == 0) { if (entry.StringID > 0) { entry.Index = -1; } else { entry.Index = 0; } } else { entry.Index = i; i++; var binaryData = new List <BitArray>(); int binaryLength = 0; /* for every character in a string, put it's binary code into data array */ foreach (char c in entry.ASCIIData) { binaryData.Add(_huffmanCodes[c]); binaryLength += _huffmanCodes[c].Count; } byte[] buffer = BitArrayListToByteArray(binaryData, binaryLength); encodedStrings.Add(new EncodedString(entry.ASCIIData.Length, buffer.Length, buffer)); } } /* writing properties */ export.WriteProperty(new IntProperty(_inputData.Count, "m_nHashTableSize")); MemoryStream m = new MemoryStream(); /* writing entries */ m.Write(BitConverter.GetBytes(_inputData.Count), 0, 4); foreach (TLKStringRef entry in _inputData) { m.Write(BitConverter.GetBytes(entry.StringID), 0, 4); m.Write(BitConverter.GetBytes(entry.Flags), 0, 4); m.Write(BitConverter.GetBytes(entry.Index), 0, 4); } /* writing HuffmanTree */ m.Write(treeBuffer, 0, treeBuffer.Length); /* writing data */ m.Write(BitConverter.GetBytes(encodedStrings.Count), 0, 4); foreach (EncodedString enc in encodedStrings) { m.Write(BitConverter.GetBytes(enc.stringLength), 0, 4); m.Write(BitConverter.GetBytes(enc.encodedLength), 0, 4); m.Write(enc.binaryData, 0, enc.encodedLength); } byte[] buff = m.ToArray(); export.WriteBinary(buff); if (savePackage) { export.FileRef.Save(export.FileRef.FilePath); } }
public static bool RandomizeExport(ExportEntry exp, RandomizationOption option) { if (!CanRandomize(exp)) { return(false); } //if (exp.UIndex != 1999) return false; try { //Log.Information($"[{Path.GetFileNameWithoutExtension(exp.FileRef.FilePath)}] Randomizing FaceFX export {exp.UIndex}"); //var d = exp.Data; var animSet = ObjectBinary.From <FaceFXAnimSet>(exp); for (int i = 0; i < animSet.Lines.Count(); i++) { var faceFxline = animSet.Lines[i]; //if (true) bool randomizedBoneList = false; if (ThreadSafeRandom.Next(10 - (int)option.SliderValue) == 0) { //Randomize the names used for animation faceFxline.AnimationNames.Shuffle(); randomizedBoneList = true; } if (!randomizedBoneList || ThreadSafeRandom.Next(16 - (int)option.SliderValue) == 0) // if bonelist was shuffled, or if 1 in 16 chance while it was also shuffled. { //Randomize the points for (int j = 0; j < faceFxline.Points.Count; j++) { bool isLast = j == faceFxline.Points.Count - 1; var currentPoint = faceFxline.Points[j]; switch (option.SliderValue) { case 1: //A few broken bones currentPoint.weight += ThreadSafeRandom.NextFloat(-.25, .25); break; case 2: //A significant option.SliderValue of broken bones currentPoint.weight += ThreadSafeRandom.NextFloat(-.5, .5); break; case 3: //That's not how the face is supposed to work if (ThreadSafeRandom.Next(5) == 0) { currentPoint.weight = ThreadSafeRandom.NextFloat(-3, 3); } else if (isLast && ThreadSafeRandom.Next(3) == 0) { currentPoint.weight = ThreadSafeRandom.NextFloat(.7, .7); } else { currentPoint.weight *= 8; } break; case 4: //:O if (ThreadSafeRandom.Next(12) == 0) { currentPoint.weight = ThreadSafeRandom.NextFloat(-5, 5); } else if (isLast && ThreadSafeRandom.Next(2) == 0) { currentPoint.weight = ThreadSafeRandom.NextFloat(.9, .9); } else { currentPoint.weight *= 5; } //Debug.WriteLine(currentPoint.weight); break; case 5: //Utter madness currentPoint.weight = ThreadSafeRandom.NextFloat(-10, 10); break; default: Debugger.Break(); break; } //if (currentPoint.weight == 0) //Debug.WriteLine($"Weight is 0, {faceFxline.NameAsString}, exp {exp.UIndex} {exp.FullPath}"); faceFxline.Points[j] = currentPoint; //Reassign the struct } } //Debugging only: Get list of all animation names //for (int j = 0; j < faceFxline.animations.Length; j++) //{ // var animationName = animSet.Header.Names[faceFxline.animations[j].index]; //animation name // faceFxBoneNames.Add(animationName); //} } //var dataBefore = exp.Data; exp.WriteBinary(animSet); //var dataAfter = exp.Data; //if (dataBefore.SequenceEqual(dataAfter)) //{ //Debugger.Break(); //} //else //{ // Log.Information($"[{Path.GetFileNameWithoutExtension(exp.FileRef.FilePath)}] Randomized FaceFX for export " + exp.UIndex); // } return(true); } catch (Exception e) { //Do nothing for now. Log.Error("AnimSet error! " + App.FlattenException((e))); } return(false); }
public static string GenerateUDKFileForLevel(string udkPath, IMEPackage pcc) { #region AssetPackage string meshPackageName = $"{Path.GetFileNameWithoutExtension(pcc.FilePath)}Meshes"; string meshFile = Path.Combine(udkPath, @"UDKGame\Content\Shared\", $"{meshPackageName}.upk"); MEPackageHandler.CreateAndSavePackage(meshFile, MEGame.UDK); using IMEPackage meshPackage = MEPackageHandler.OpenUDKPackage(meshFile); meshPackage.getEntryOrAddImport("Core.Package"); IEntry defMat = meshPackage.getEntryOrAddImport("EngineMaterials.DefaultMaterial", "Material", "Engine"); var allMats = new HashSet <int>(); var relinkMap = new Dictionary <IEntry, IEntry>(); #region StaticMeshes List <ExportEntry> staticMeshes = pcc.Exports.Where(exp => exp.ClassName == "StaticMesh").ToList(); foreach (ExportEntry mesh in staticMeshes) { var mats = new Queue <int>(); StaticMesh stm = ObjectBinary.From <StaticMesh>(mesh); foreach (StaticMeshRenderData lodModel in stm.LODModels) { foreach (StaticMeshElement meshElement in lodModel.Elements) { mats.Enqueue(meshElement.Material); allMats.Add(meshElement.Material); meshElement.Material = 0; } } if (pcc.GetEntry(stm.BodySetup) is ExportEntry rbBodySetup) { rbBodySetup.RemoveProperty("PhysMaterial"); } mesh.WriteBinary(stm); IEntry newParent = EntryImporter.GetOrAddCrossImportOrPackage(mesh.ParentFullPath, pcc, meshPackage); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, mesh, meshPackage, newParent, false, out IEntry ent, relinkMap); ExportEntry portedMesh = (ExportEntry)ent; stm = ObjectBinary.From <StaticMesh>(portedMesh); foreach (StaticMeshRenderData lodModel in stm.LODModels) { foreach (StaticMeshElement meshElement in lodModel.Elements) { meshElement.Material = mats.Dequeue(); } } portedMesh.WriteBinary(stm); } #endregion #region Materials using (IMEPackage udkResources = MEPackageHandler.OpenMEPackageFromStream(Utilities.GetCustomAppResourceStream(MEGame.UDK))) { ExportEntry normDiffMat = udkResources.Exports.First(exp => exp.ObjectName == "NormDiffMat"); foreach (int matUIndex in allMats) { if (pcc.GetEntry(matUIndex) is ExportEntry matExp) { List <IEntry> textures = new MaterialInstanceConstant(matExp).Textures; ExportEntry diff = null; ExportEntry norm = null; foreach (IEntry texEntry in textures) { if (texEntry is ExportEntry texport) { if (texport.ObjectName.Name.ToLower().Contains("diff")) { diff = texport; } else if (texport.ObjectName.Name.ToLower().Contains("norm")) { norm = texport; } } } if (diff == null) { relinkMap[matExp] = defMat; continue; } else { EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, diff, meshPackage, null, false, out IEntry ent); diff = (ExportEntry)ent; diff.RemoveProperty("TextureFileCacheName"); diff.RemoveProperty("TFCFileGuid"); diff.RemoveProperty("LODGroup"); } if (norm != null) { EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, norm, meshPackage, null, false, out IEntry ent); norm = (ExportEntry)ent; norm.RemoveProperty("TextureFileCacheName"); norm.RemoveProperty("TFCFileGuid"); norm.RemoveProperty("LODGroup"); } EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, normDiffMat, meshPackage, null, true, out IEntry matEnt); ExportEntry newMat = (ExportEntry)matEnt; newMat.ObjectName = matExp.ObjectName; Material matBin = ObjectBinary.From <Material>(newMat); matBin.SM3MaterialResource.UniformExpressionTextures = new UIndex[] { norm?.UIndex ?? 0, diff.UIndex }; newMat.WriteBinary(matBin); relinkMap[matExp] = newMat; if (newMat.GetProperty <ArrayProperty <ObjectProperty> >("Expressions") is {} expressionsProp&& expressionsProp.Count >= 2) { ExportEntry diffExpression = meshPackage.GetUExport(expressionsProp[0].Value); ExportEntry normExpression = meshPackage.GetUExport(expressionsProp[1].Value); diffExpression.WriteProperty(new ObjectProperty(diff.UIndex, "Texture")); normExpression.WriteProperty(new ObjectProperty(norm?.UIndex ?? 0, "Texture")); } } else if (pcc.GetEntry(matUIndex) is ImportEntry matImp) { relinkMap[matImp] = defMat; } } var relinkMapping = new OrderedMultiValueDictionary <IEntry, IEntry>(relinkMap); foreach (ExportEntry stmExport in staticMeshes) { if (relinkMap.TryGetValue(stmExport, out IEntry destEnt) && destEnt is ExportEntry destExp) { Relinker.Relink(stmExport, destExp, relinkMapping); } } } #endregion meshPackage.Save(); #endregion var staticMeshActors = new List <ExportEntry>(); var lightActors = new List <ExportEntry>(); string tempPackagePath = Path.Combine(App.ExecFolder, $"{Path.GetFileNameWithoutExtension(pcc.FilePath)}.udk"); File.Copy(Path.Combine(App.ExecFolder, "empty.udk"), tempPackagePath, true); using IMEPackage udkPackage = MEPackageHandler.OpenUDKPackage(tempPackagePath); { var topLevelMeshPackages = new List <IEntry>(); foreach (ExportEntry exportEntry in staticMeshes) { IEntry imp = udkPackage.getEntryOrAddImport($"{exportEntry.FullPath}", "StaticMesh", "Engine", exportEntry.ObjectName.Number); while (imp.Parent != null) { imp = imp.Parent; } if (!topLevelMeshPackages.Contains(imp)) { topLevelMeshPackages.Add(imp); } } ExportEntry levelExport = udkPackage.Exports.First(exp => exp.ClassName == "Level"); List <int> actorsInLevel = ObjectBinary.From <Level>(pcc.Exports.First(exp => exp.ClassName == "Level")).Actors.Select(u => u.value).ToList(); var componentToMatrixMap = new Dictionary <int, Matrix>(); foreach (int uIndex in actorsInLevel) { if (pcc.GetEntry(uIndex) is ExportEntry stcExp) { if (stcExp.ClassName == "StaticMeshCollectionActor") { StaticMeshCollectionActor stmc = ObjectBinary.From <StaticMeshCollectionActor>(stcExp); var components = stcExp.GetProperty <ArrayProperty <ObjectProperty> >("StaticMeshComponents"); for (int i = 0; i < components.Count; i++) { componentToMatrixMap[components[i].Value] = stmc.LocalToWorldTransforms[i]; } } else if (stcExp.ClassName == "StaticLightCollectionActor") { StaticLightCollectionActor stlc = ObjectBinary.From <StaticLightCollectionActor>(stcExp); var components = stcExp.GetProperty <ArrayProperty <ObjectProperty> >("LightComponents"); for (int i = 0; i < components.Count; i++) { componentToMatrixMap[components[i].Value] = stlc.LocalToWorldTransforms[i]; } } } } #region StaticMeshActors { var emptySMCBin = new StaticMeshComponent(); IEntry staticMeshActorClass = udkPackage.getEntryOrAddImport("Engine.StaticMeshActor"); udkPackage.getEntryOrAddImport("Engine.Default__StaticMeshActor", "StaticMeshActor", "Engine"); IEntry staticMeshComponentArchetype = udkPackage.getEntryOrAddImport("Engine.Default__StaticMeshActor.StaticMeshComponent0", "StaticMeshComponent", "Engine"); int smaIndex = 2; int smcIndex = 2; foreach (ExportEntry smc in pcc.Exports.Where(exp => exp.ClassName == "StaticMeshComponent")) { if (smc.Parent is ExportEntry parent && actorsInLevel.Contains(parent.UIndex) && parent.IsA("StaticMeshActorBase")) { StructProperty locationProp; StructProperty rotationProp; StructProperty scaleProp = null; smc.CondenseArchetypes(); if (!(smc.GetProperty <ObjectProperty>("StaticMesh") is { } meshProp) || !pcc.IsUExport(meshProp.Value)) { continue; } smc.WriteBinary(emptySMCBin); smc.RemoveProperty("bBioIsReceivingDecals"); smc.RemoveProperty("bBioForcePrecomputedShadows"); //smc.RemoveProperty("bUsePreComputedShadows"); smc.RemoveProperty("bAcceptsLights"); smc.RemoveProperty("IrrelevantLights"); smc.RemoveProperty("Materials"); //should make use of this? smc.ObjectName = new NameReference("StaticMeshComponent", smcIndex++); if (parent.ClassName == "StaticMeshCollectionActor") { if (!componentToMatrixMap.TryGetValue(smc.UIndex, out Matrix m)) { continue; } (Vector3 posVec, Vector3 scaleVec, Rotator rotator) = m.UnrealDecompose(); locationProp = CommonStructs.Vector3Prop(posVec, "Location"); rotationProp = CommonStructs.RotatorProp(rotator, "Rotation"); scaleProp = CommonStructs.Vector3Prop(scaleVec, "DrawScale3D"); //smc.WriteProperty(CommonStructs.Matrix(m, "CachedParentToWorld")); } else { locationProp = parent.GetProperty <StructProperty>("Location"); rotationProp = parent.GetProperty <StructProperty>("Rotation"); scaleProp = parent.GetProperty <StructProperty>("DrawScale3D"); if (parent.GetProperty <FloatProperty>("DrawScale")?.Value is float scale) { Vector3 scaleVec = Vector3.One; if (scaleProp != null) { scaleVec = CommonStructs.GetVector3(scaleProp); } scaleProp = CommonStructs.Vector3Prop(scaleVec * scale, "DrawScale3D"); } } ExportEntry sma = new ExportEntry(udkPackage, EntryImporter.CreateStack(MEGame.UDK, staticMeshActorClass.UIndex)) { ObjectName = new NameReference("StaticMeshActor", smaIndex++), Class = staticMeshActorClass, Parent = levelExport }; sma.ObjectFlags |= UnrealFlags.EObjectFlags.HasStack; udkPackage.AddExport(sma); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, smc, udkPackage, sma, true, out IEntry result); var props = new PropertyCollection { new ObjectProperty(result.UIndex, "StaticMeshComponent"), new NameProperty(new NameReference(Path.GetFileNameWithoutExtension(smc.FileRef.FilePath), smc.UIndex), "Tag"), new ObjectProperty(result.UIndex, "CollisionComponent") }; if (locationProp != null) { props.Add(locationProp); } if (rotationProp != null) { props.Add(rotationProp); } if (scaleProp != null) { props.Add(scaleProp); } sma.WriteProperties(props); staticMeshActors.Add(sma); } } IEntry topMeshPackageImport = udkPackage.getEntryOrAddImport(meshPackageName, "Package"); foreach (IEntry mp in topLevelMeshPackages) { mp.Parent = topMeshPackageImport; } } #endregion #region LightActors { IEntry pointLightClass = udkPackage.getEntryOrAddImport("Engine.PointLight"); IEntry spotLightClass = udkPackage.getEntryOrAddImport("Engine.SpotLight"); IEntry directionalLightClass = udkPackage.getEntryOrAddImport("Engine.DirectionalLight"); int plaIndex = 1; int plcIndex = 1; int slaIndex = 1; int slcIndex = 1; int dlaIndex = 1; int dlcIndex = 1; foreach (ExportEntry lightComponent in pcc.Exports) { if (!(lightComponent.Parent is ExportEntry parent && actorsInLevel.Contains(parent.UIndex))) { continue; } StructProperty locationProp; StructProperty rotationProp; StructProperty scaleProp; switch (lightComponent.ClassName) { case "PointLightComponent": lightComponent.CondenseArchetypes(); lightComponent.ObjectName = new NameReference("PointLightComponent", plcIndex++); if (parent.ClassName == "StaticLightCollectionActor") { if (!componentToMatrixMap.TryGetValue(lightComponent.UIndex, out Matrix m)) { continue; } (Vector3 posVec, Vector3 scaleVec, Rotator rotator) = m.UnrealDecompose(); locationProp = CommonStructs.Vector3Prop(posVec, "Location"); rotationProp = CommonStructs.RotatorProp(rotator, "Rotation"); scaleProp = CommonStructs.Vector3Prop(scaleVec, "DrawScale3D"); } else { locationProp = parent.GetProperty <StructProperty>("Location"); rotationProp = parent.GetProperty <StructProperty>("Rotation"); scaleProp = parent.GetProperty <StructProperty>("DrawScale3D"); if (parent.GetProperty <FloatProperty>("DrawScale")?.Value is float scale) { Vector3 scaleVec = Vector3.One; if (scaleProp != null) { scaleVec = CommonStructs.GetVector3(scaleProp); } scaleProp = CommonStructs.Vector3Prop(scaleVec * scale, "DrawScale3D"); } } ExportEntry pla = new ExportEntry(udkPackage, EntryImporter.CreateStack(MEGame.UDK, pointLightClass.UIndex)) { ObjectName = new NameReference("PointLight", plaIndex++), Class = pointLightClass, Parent = levelExport }; pla.ObjectFlags |= UnrealFlags.EObjectFlags.HasStack; udkPackage.AddExport(pla); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, lightComponent, udkPackage, pla, true, out IEntry portedPLC); var plsProps = new PropertyCollection { new ObjectProperty(portedPLC.UIndex, "LightComponent"), new NameProperty("PointLight", "Tag"), }; if (locationProp != null) { plsProps.Add(locationProp); } if (rotationProp != null) { plsProps.Add(rotationProp); } if (scaleProp != null) { plsProps.Add(scaleProp); } pla.WriteProperties(plsProps); lightActors.Add(pla); break; case "SpotLightComponent": lightComponent.CondenseArchetypes(); lightComponent.ObjectName = new NameReference("SpotLightComponent", slcIndex++); if (parent.ClassName == "StaticLightCollectionActor") { if (!componentToMatrixMap.TryGetValue(lightComponent.UIndex, out Matrix m)) { continue; } (Vector3 posVec, Vector3 scaleVec, Rotator rotator) = m.UnrealDecompose(); locationProp = CommonStructs.Vector3Prop(posVec, "Location"); rotationProp = CommonStructs.RotatorProp(rotator, "Rotation"); scaleProp = CommonStructs.Vector3Prop(scaleVec, "DrawScale3D"); } else { locationProp = parent.GetProperty <StructProperty>("Location"); rotationProp = parent.GetProperty <StructProperty>("Rotation"); scaleProp = parent.GetProperty <StructProperty>("DrawScale3D"); if (parent.GetProperty <FloatProperty>("DrawScale")?.Value is float scale) { Vector3 scaleVec = Vector3.One; if (scaleProp != null) { scaleVec = CommonStructs.GetVector3(scaleProp); } scaleProp = CommonStructs.Vector3Prop(scaleVec * scale, "DrawScale3D"); } } ExportEntry sla = new ExportEntry(udkPackage, EntryImporter.CreateStack(MEGame.UDK, spotLightClass.UIndex)) { ObjectName = new NameReference("SpotLight", slaIndex++), Class = spotLightClass, Parent = levelExport }; sla.ObjectFlags |= UnrealFlags.EObjectFlags.HasStack; udkPackage.AddExport(sla); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, lightComponent, udkPackage, sla, true, out IEntry portedSLC); var slaProps = new PropertyCollection { new ObjectProperty(portedSLC.UIndex, "LightComponent"), new NameProperty("SpotLight", "Tag"), }; if (locationProp != null) { slaProps.Add(locationProp); } if (rotationProp != null) { slaProps.Add(rotationProp); } if (scaleProp != null) { slaProps.Add(scaleProp); } sla.WriteProperties(slaProps); lightActors.Add(sla); break; case "DirectionalLightComponent": lightComponent.CondenseArchetypes(); lightComponent.ObjectName = new NameReference("DirectionalLightComponent", dlcIndex++); if (parent.ClassName == "StaticLightCollectionActor") { if (!componentToMatrixMap.TryGetValue(lightComponent.UIndex, out Matrix m)) { continue; } (Vector3 posVec, Vector3 scaleVec, Rotator rotator) = m.UnrealDecompose(); locationProp = CommonStructs.Vector3Prop(posVec, "Location"); rotationProp = CommonStructs.RotatorProp(rotator, "Rotation"); scaleProp = CommonStructs.Vector3Prop(scaleVec, "DrawScale3D"); } else { locationProp = parent.GetProperty <StructProperty>("Location"); rotationProp = parent.GetProperty <StructProperty>("Rotation"); scaleProp = parent.GetProperty <StructProperty>("DrawScale3D"); if (parent.GetProperty <FloatProperty>("DrawScale")?.Value is float scale) { Vector3 scaleVec = Vector3.One; if (scaleProp != null) { scaleVec = CommonStructs.GetVector3(scaleProp); } scaleProp = CommonStructs.Vector3Prop(scaleVec * scale, "DrawScale3D"); } } ExportEntry dla = new ExportEntry(udkPackage, EntryImporter.CreateStack(MEGame.UDK, directionalLightClass.UIndex)) { ObjectName = new NameReference("DirectionalLight", dlaIndex++), Class = directionalLightClass, Parent = levelExport }; dla.ObjectFlags |= UnrealFlags.EObjectFlags.HasStack; udkPackage.AddExport(dla); EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.AddSingularAsChild, lightComponent, udkPackage, dla, true, out IEntry portedDLC); var dlaProps = new PropertyCollection { new ObjectProperty(portedDLC.UIndex, "LightComponent"), new NameProperty("DirectionalLight", "Tag"), }; if (locationProp != null) { dlaProps.Add(locationProp); } if (rotationProp != null) { dlaProps.Add(rotationProp); } if (scaleProp != null) { dlaProps.Add(scaleProp); } dla.WriteProperties(dlaProps); lightActors.Add(dla); break; } } } UDKifyLights(udkPackage); #endregion Level level = ObjectBinary.From <Level>(levelExport); level.Actors = levelExport.GetChildren().Where(ent => ent.IsA("Actor")).Select(ent => new UIndex(ent.UIndex)).ToList(); levelExport.WriteBinary(level); udkPackage.Save(); } string resultFilePath = Path.Combine(udkPath, @"UDKGame\Content\Maps\", $"{Path.GetFileNameWithoutExtension(pcc.FilePath)}.udk"); using (IMEPackage udkPackage2 = MEPackageHandler.OpenUDKPackage(Path.Combine(App.ExecFolder, "empty.udk"))) { ExportEntry levelExport = udkPackage2.Exports.First(exp => exp.ClassName == "Level"); Level levelBin = ObjectBinary.From <Level>(levelExport); foreach (ExportEntry actor in staticMeshActors) { EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, actor, udkPackage2, levelExport, true, out IEntry result); levelBin.Actors.Add(result.UIndex); } foreach (ExportEntry actor in lightActors) { EntryImporter.ImportAndRelinkEntries(EntryImporter.PortingOption.CloneTreeAsChild, actor, udkPackage2, levelExport, true, out IEntry result); levelBin.Actors.Add(result.UIndex); } levelExport.WriteBinary(levelBin); udkPackage2.Save(resultFilePath); } File.Delete(tempPackagePath); return(resultFilePath); }
/* * private static void VerifyGesturesWork(ExportEntry trackExport) * { * var gestures = RBioEvtSysTrackGesture.GetGestures(trackExport); * var defaultPose = RBioEvtSysTrackGesture.GetDefaultPose(trackExport); * * var gesturesToCheck = gestures.Append(defaultPose).ToList(); * * // Get the containing sequence * var owningSequence = SeqTools.GetParentSequence(trackExport); * while (owningSequence.ClassName != "Sequence") * { * owningSequence = owningSequence.Parent as ExportEntry; * var parSeq = SeqTools.GetParentSequence(owningSequence); * if (parSeq != null) * { * owningSequence = parSeq; * } * } * * var kismetBioDynamicAnimSets = owningSequence.GetProperty<ArrayProperty<ObjectProperty>>("m_aBioDynAnimSets"); * if (kismetBioDynamicAnimSets == null) * { * // We don't have any animsets! * throw new Exception("Track's sequence is missing animsets property!"); * } * * // Get a list of all supported animations * List<Gesture> supportedGestures = new List<Gesture>(); * foreach (var kbdas in kismetBioDynamicAnimSets) * { * var sequenceBioDynamicAnimSet = kbdas.ResolveToEntry(trackExport.FileRef) as ExportEntry; // I don't think these can be imports as they're part of the seq * var associatedset = sequenceBioDynamicAnimSet.GetProperty<ObjectProperty>("m_pBioAnimSetData").ResolveToEntry(trackExport.FileRef); * * } * * // Check all gestures * foreach (var gesture in gesturesToCheck) * { * var bioAnimSet = gesture.GetBioAnimSet(trackExport.FileRef); * * } * * * * } * * internal class TestingBioDynamicAnimSet * { * public NameReference OrigSetName { get; } * public List<string> SupportedGesturesFullPaths { get; } * public IEntry BioAnimSetData { get; } * * internal TestingBioDynamicAnimSet(ExportEntry export) * { * var props = export.GetProperties(); * OrigSetName = props.GetProp<NameProperty>("m_nmOrigSetName").Value; * BioAnimSetData = props.GetProp<ObjectProperty>("m_pBioAnimSetData").ResolveToEntry(export.FileRef); * SupportedGesturesFullPaths = props.GetProp<ArrayProperty<ObjectProperty>>("Sequences").Select(x => x.ResolveToEntry(export.FileRef).InstancedFullPath).ToList(); * } * } */ private static void InstallDynamicAnimSetRefForSeq(ref ExportEntry owningSequence, ExportEntry export, Gesture gesture) { // Find owning sequence if (owningSequence == null) { owningSequence = export; } while (owningSequence.ClassName != "Sequence") { owningSequence = owningSequence.Parent as ExportEntry; var parSeq = SeqTools.GetParentSequence(owningSequence); if (parSeq != null) { owningSequence = parSeq; } } // We have parent sequence data var kismetBioDynamicAnimSets = owningSequence.GetProperty <ArrayProperty <ObjectProperty> >("m_aBioDynAnimSets") ?? new ArrayProperty <ObjectProperty>("m_aBioDynamicAnimSets"); // Check to see if there is any item that uses our bioanimset var bioAnimSet = gesture.GetBioAnimSet(export.FileRef); if (bioAnimSet != null) { ExportEntry kismetBDAS = null; foreach (var kbdas in kismetBioDynamicAnimSets) { var kEntry = kbdas.ResolveToEntry(export.FileRef) as ExportEntry; // I don't think these can be imports as they're part of the seq var associatedset = kEntry.GetProperty <ObjectProperty>("m_pBioAnimSetData").ResolveToEntry(export.FileRef); if (associatedset == bioAnimSet) { // It's this one kismetBDAS = kEntry; break; } } if (kismetBDAS == null) { // We need to generate a new one PropertyCollection props = new PropertyCollection(); props.Add(new NameProperty(gesture.GestureSet, "m_nmOrigSetName")); props.Add(new ArrayProperty <ObjectProperty>("Sequences")); props.Add(new ObjectProperty(bioAnimSet, "m_pBioAnimSetData")); kismetBDAS = ExportCreator.CreateExport(export.FileRef, $"KIS_DYN_{gesture.GestureSet}", "BioDynamicAnimSet", owningSequence); kismetBDAS.indexValue = 0; // Write a blank count of 0 - we will update this in subsequent call // This must be here to ensure parser can read it kismetBDAS.WritePropertiesAndBinary(props, new byte[4]); kismetBioDynamicAnimSets.Add(new ObjectProperty(kismetBDAS)); // Add new export to sequence's list of biodynamicanimsets owningSequence.WriteProperty(kismetBioDynamicAnimSets); } var currentObjs = kismetBDAS.GetProperty <ArrayProperty <ObjectProperty> >("Sequences"); if (currentObjs.All(x => x.Value != gesture.Entry.UIndex)) { // We need to add our item to it currentObjs.Add(new ObjectProperty(gesture.Entry)); var bin = ObjectBinary.From <BioDynamicAnimSet>(kismetBDAS); bin.SequenceNamesToUnkMap[gesture.GestureAnim] = 1; // Not sure what the value should be, or if game actually reads this // FIX IT IF WE EVER FIGURE IT OUT! kismetBDAS.WriteProperty(currentObjs); kismetBDAS.WriteBinary(bin); } } }
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 void CompactShaderCaches(IMEPackage mePackage) { var staticParamSetsInFile = new HashSet <StaticParameterSet>(); //figure out which MaterialShaderMaps to keep foreach (ExportEntry export in mePackage.Exports) { if (export.ClassName == "Material") { staticParamSetsInFile.Add((StaticParameterSet)ObjectBinary.From <Material>(export).SM3MaterialResource.ID); } else if (export.IsA("MaterialInstance") && export.GetProperty <BoolProperty>("bHasStaticPermutationResource")) { staticParamSetsInFile.Add(ObjectBinary.From <MaterialInstance>(export).SM3StaticParameterSet); } } var compactedShaderCache = new ShaderCache { Shaders = new OrderedMultiValueDictionary <Guid, Shader>(), MaterialShaderMaps = new OrderedMultiValueDictionary <StaticParameterSet, MaterialShaderMap>() }; //add MaterialShaderMaps foreach (ExportEntry shaderCacheExport in mePackage.Exports.Where(exp => exp.ClassName == "ShaderCache")) { var shaderCache = ObjectBinary.From <ShaderCache>(shaderCacheExport); compactedShaderCache.ShaderTypeCRCMap = shaderCache.ShaderTypeCRCMap; compactedShaderCache.VertexFactoryTypeCRCMap = shaderCache.VertexFactoryTypeCRCMap; foreach ((StaticParameterSet key, MaterialShaderMap msm) in shaderCache.MaterialShaderMaps) { if (staticParamSetsInFile.Any(sps => sps == key) && !compactedShaderCache.MaterialShaderMaps.ContainsKey(key)) { compactedShaderCache.MaterialShaderMaps.Add(key, msm); } } } //Figure out which shaders to keep var shaderGuids = new HashSet <Guid>(); foreach ((_, MaterialShaderMap materialShaderMap) in compactedShaderCache.MaterialShaderMaps) { foreach ((_, ShaderReference shaderRef) in materialShaderMap.Shaders) { shaderGuids.Add(shaderRef.Id); } foreach (MeshShaderMap meshShaderMap in materialShaderMap.MeshShaderMaps) { foreach ((_, ShaderReference shaderRef) in meshShaderMap.Shaders) { shaderGuids.Add(shaderRef.Id); } } } ExportEntry firstShaderCache = null; //add Shaders foreach (ExportEntry shaderCacheExport in mePackage.Exports.Where(exp => exp.ClassName == "ShaderCache")) { var shaderCache = ObjectBinary.From <ShaderCache>(shaderCacheExport); foreach ((Guid key, Shader shader) in shaderCache.Shaders) { if (shaderGuids.Contains(key) && !compactedShaderCache.Shaders.ContainsKey(key)) { compactedShaderCache.Shaders.Add(key, shader); } } if (firstShaderCache == null) { firstShaderCache = shaderCacheExport; } else { EntryPruner.TrashEntryAndDescendants(shaderCacheExport); } } firstShaderCache.WriteBinary(compactedShaderCache); }