예제 #1
0
        /// <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);
            }
        }
예제 #2
0
        /// <summary>
        /// ME2 SPECIFIC<para/>
        /// Repoint a WwiseStream to play the data from another, typically across banks.
        /// </summary>
        /// <param name="originalExport">The audio you want to play (e.g. this is the audio that will be 'installed')</param>
        /// <param name="targetAudioStream">The audio stream that you want to replace.</param>
        public static void RepointWwiseStream(ExportEntry originalExport, ExportEntry targetAudioStream)
        {
            var props    = originalExport.GetProperties();
            var bin      = ObjectBinary.From <WwiseStream>(originalExport);
            var targetId = targetAudioStream.GetProperty <IntProperty>("Id");

            props.AddOrReplaceProp(targetId);
            targetAudioStream.WritePropertiesAndBinary(props, bin);
        }
예제 #3
0
        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);
                }
            }
        }
예제 #4
0
        /// <summary>
        /// ME2 SPECIFIC<para/>
        /// Repoint a WwiseStream to play the data from another precomputed stream.
        /// </summary>
        /// <param name="originalExport">The audio you want to play (e.g. this is the audio that will be 'installed')</param>
        /// <param name="targetAudioStream">The audio stream that you want to replace.</param>
        public static void RepointWwiseStreamToInfo(RMusic.MusicStreamInfo streamInfo, ExportEntry targetAudioStream)
        {
            WwiseStream stream = new WwiseStream();

            stream.Filename   = ""; // Just make sure it's not set to null so internal code thinks this is not Pcc stored.
            stream.DataSize   = streamInfo.DataSize;
            stream.Unk1       = stream.Unk2 = stream.Unk3 = stream.Unk4 = stream.Unk5 = 1;
            stream.UnkGuid    = streamInfo.UnkGuid;
            stream.DataOffset = streamInfo.DataOffset;

            PropertyCollection props = new PropertyCollection();

            props.Add(targetAudioStream.GetProperty <IntProperty>("Id")); // Use the existing Id
            props.Add(new NameProperty(streamInfo.Filename, "Filename")); // AFC file
            props.Add(new NameProperty(streamInfo.BankName, "BankName")); // ?
            targetAudioStream.WritePropertiesAndBinary(props, stream);
        }
예제 #5
0
        /*
         * 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);
                }
            }
        }