示例#1
0
        public void Deserialize(IMEPackage pcc)
        {
            PropertyCollection properties = pcc.Exports[Index].GetProperties();

            if (pcc.Game == MEGame.ME3)
            {
                int off = pcc.Exports[Index].propsEnd() + 8;
                ValueOffset = off;
                DataSize    = BitConverter.ToInt32(memory, off);
                DataOffset  = BitConverter.ToInt32(memory, off + 4);
            }
            else if (pcc.Game == MEGame.ME2)
            {
                int off = pcc.Exports[Index].propsEnd() + 0x28;
                ValueOffset = off;
                DataSize    = BitConverter.ToInt32(memory, off);
                DataOffset  = BitConverter.ToInt32(memory, off + 4);
            }
            NameProperty nameProp = properties.GetProp <NameProperty>("Filename");

            FileName = nameProp != null ? nameProp.Value : null;
            Id       = properties.GetProp <IntProperty>("Id");

            /*for (int i = 0; i < props.Count; i++)
             * {
             *  if (pcc.Names[props[i].Name] == "Filename")
             *      FileName = pcc.Names[props[i].Value.IntValue];
             *  if (pcc.Names[props[i].Name] == "Id")
             *      Id = props[i].Value.IntValue;
             * }*/
        }
示例#2
0
        public void Deserialize(IMEPackage pcc)
        {
            PropertyCollection properties = export.GetProperties();
            int off;

            switch (pcc.Game)
            {
            case MEGame.ME3:
                off = export.propsEnd() + 8;
                break;

            case MEGame.ME2:
                off = export.propsEnd() + 0x28;
                break;

            default:
                throw new Exception("Can oly read WwiseStreams for ME3 and ME2!");
            }
            ValueOffset = off;
            DataSize    = BitConverter.ToInt32(memory, off);
            DataOffset  = BitConverter.ToInt32(memory, off + 4);
            NameProperty nameProp = properties.GetProp <NameProperty>("Filename");

            FileName = nameProp?.Value;
            Id       = properties.GetProp <IntProperty>("Id");
        }
示例#3
0
        public static uint GetTextureCRC(ExportEntry export)
        {
            PropertyCollection properties = export.GetProperties();
            var format = properties.GetProp <EnumProperty>("Format");
            var cache  = properties.GetProp <NameProperty>("TextureFileCacheName");
            List <Texture2DMipInfo> mips = Texture2D.GetTexture2DMipInfos(export, cache != null ? cache.Value : null);
            var topmip = mips.FirstOrDefault(x => x.storageType != StorageTypes.empty);

            return(Texture2D.GetMipCRC(topmip, format.Value));
        }
示例#4
0
        /// <summary>
        /// Modifies the incoming properties collection to update the spec size
        /// </summary>
        /// <param name="specProperties"></param>
        /// <param name="radius"></param>
        /// <param name="height"></param>
        public static void SetReachSpecSize(PropertyCollection specProperties, int radius, int height)
        {
            IntProperty radiusProp = specProperties.GetProp <IntProperty>("CollisionRadius");
            IntProperty heightProp = specProperties.GetProp <IntProperty>("CollisionHeight");

            if (radiusProp != null)
            {
                radiusProp.Value = radius;
            }
            if (heightProp != null)
            {
                heightProp.Value = height;
            }
        }
示例#5
0
        public static bool RandomizeExport(ExportEntry export, RandomizationOption option)
        {
            if (!CanRandomize(export))
            {
                return(false);
            }
            PropertyCollection props = export.GetProperties();
            var colorOverrides       = props.GetProp <ArrayProperty <StructProperty> >("m_aColorOverrides");

            if (colorOverrides != null)
            {
                foreach (StructProperty colorParameter in colorOverrides)
                {
                    //Debug.WriteLine("Randomizing Color Parameter");
                    RStructs.RandomizeTint(colorParameter.GetProp <StructProperty>("cValue"), false);
                }
            }
            var scalarOverrides = props.GetProp <ArrayProperty <StructProperty> >("m_aScalarOverrides");

            if (scalarOverrides != null)
            {
                foreach (StructProperty scalarParameter in scalarOverrides)
                {
                    var name = scalarParameter.GetProp <NameProperty>("nName");
                    if (name != null)
                    {
                        if (name.Value.Name.Contains("_Frek_") || name.Value.Name.StartsWith("HAIR") || name.Value.Name.StartsWith("HED_Scar"))
                        {
                            var currentValue = scalarParameter.GetProp <FloatProperty>("sValue");
                            if (currentValue != null)
                            {
                                //Debug.WriteLine("Randomizing FREK HAIR HEDSCAR");

                                if (currentValue > 1)
                                {
                                    scalarParameter.GetProp <FloatProperty>("sValue").Value = ThreadSafeRandom.NextFloat(0, currentValue * 1.3);
                                }
                                else
                                {
                                    scalarParameter.GetProp <FloatProperty>("sValue").Value = ThreadSafeRandom.NextFloat(0, 1);
                                }
                            }
                        }
                    }
                }
            }
            export.WriteProperties(props);
            return(true);
        }
示例#6
0
        public Texture2D(ExportEntry export)
        {
            Export = export;
            PropertyCollection properties = export.GetProperties();

            TextureFormat = properties.GetProp <EnumProperty>("Format").Value.Name;
            var cache = properties.GetProp <NameProperty>("TextureFileCacheName");

            NeverStream = properties.GetProp <BoolProperty>("NeverStream") ?? false;
            Mips        = GetTexture2DMipInfos(export, cache?.Value);
            if (Export.Game != Mod.MEGame.ME1)
            {
                TextureGuid = new Guid(Export.Data.Skip(Export.Data.Length - 16).Take(16).ToArray());
            }
        }
示例#7
0
        //actor must be an Actor
        public static Matrix GetLocalToWorld(ExportEntry actor)
        {
            PropertyCollection props = actor.GetProperties();
            var rotationProp         = props.GetProp <StructProperty>("Rotation");
            var locationsProp        = props.GetProp <StructProperty>("location");
            var drawScale3DProp      = props.GetProp <StructProperty>("DrawScale3D");
            var prePivotProp         = props.GetProp <StructProperty>("PrePivot");

            float drawScale = props.GetProp <FloatProperty>("DrawScale")?.Value ?? 1;

            Vector3 location = locationsProp != null?CommonStructs.GetVector3(locationsProp) : Vector3.Zero;

            Vector3 scale = drawScale * (drawScale3DProp != null ? CommonStructs.GetVector3(drawScale3DProp) : Vector3.One);
            Vector3 pivot = prePivotProp != null?CommonStructs.GetVector3(prePivotProp) : Vector3.Zero;

            Rotator rotator = rotationProp != null?CommonStructs.GetRotator(rotationProp) : new Rotator(0, 0, 0);

            return(ComposeLocalToWorld(location, rotator, scale, pivot));
        }
示例#8
0
        //public static Func<string> GetLocalizedCouldNotFetchTextureDataMessage { get; set; }

        public Texture2D(ExportEntry export)
        {
            Export = export;
            PropertyCollection properties = export.GetProperties();

            TextureFormat = properties.GetProp <EnumProperty>(@"Format").Value.Name;
            var cache = properties.GetProp <NameProperty>(@"TextureFileCacheName");

            NeverStream = properties.GetProp <BoolProperty>(@"NeverStream") ?? false;
            Mips        = GetTexture2DMipInfos(export, cache?.Value);
            if (Export.Game != MEGame.ME1)
            {
                int guidOffsetFromEnd = export.Game == MEGame.ME3 ? 20 : 16;
                if (export.ClassName == "LightMapTexture2D")
                {
                    guidOffsetFromEnd += 4;
                }
                TextureGuid = new Guid(Export.Data.Skip(Export.Data.Length - guidOffsetFromEnd).Take(16).ToArray());
            }
        }
示例#9
0
        public static Matrix GetWorldToLocal(ExportEntry actor)
        {
            PropertyCollection props = actor.GetProperties();
            var rotationProp         = props.GetProp <StructProperty>("Rotation");
            var locationsProp        = props.GetProp <StructProperty>("location");
            var drawScale3DProp      = props.GetProp <StructProperty>("DrawScale3D");
            var prePivotProp         = props.GetProp <StructProperty>("PrePivot");

            float drawScale = props.GetProp <FloatProperty>("DrawScale")?.Value ?? 1;

            Vector3 location = locationsProp != null?CommonStructs.GetVector3(locationsProp) : Vector3.Zero;

            (float scaleX, float scaleY, float scaleZ) = drawScale3DProp != null?CommonStructs.GetVector3(drawScale3DProp) : Vector3.One;

            Vector3 prePivot = prePivotProp != null?CommonStructs.GetVector3(prePivotProp) : Vector3.Zero;

            Rotator rotation = rotationProp != null?CommonStructs.GetRotator(rotationProp) : new Rotator(0, 0, 0);

            return(Matrix.Translation(-location) *
                   InverseRotation(rotation) *
                   Matrix.Scaling(new Vector3(1f / scaleX, 1f / scaleY, 1f / scaleZ) / drawScale) *
                   Matrix.Translation(prePivot));
        }
        public static void RandBool(PropertyCollection props, string propname, bool createIfMissing)
        {
            var prop = props.GetProp <BoolProperty>(propname);

            if (prop == null && createIfMissing)
            {
                prop = new BoolProperty(false, propname);
                props.Add(prop);
            }
            if (prop != null)
            {
                prop.Value = ThreadSafeRandom.Next(2) == 1;
            }
        }
        public static void RandFloat(PropertyCollection props, string propname, float min, float max, bool createIfMissing)
        {
            var prop = props.GetProp <FloatProperty>(propname);

            if (prop == null && createIfMissing)
            {
                prop = new FloatProperty(0, propname);
                props.Add(prop);
            }
            if (prop != null)
            {
                prop.Value = ThreadSafeRandom.NextFloat(min, max);
            }
        }
示例#12
0
        internal static ExportEntry GetReachSpecEndExport(ExportEntry reachSpec, PropertyCollection props = null)
        {
            if (props == null)
            {
                props = reachSpec.GetProperties();
            }

            if (props.GetProp <StructProperty>("End") is StructProperty endProperty &&
                endProperty.GetProp <ObjectProperty>(SharedPathfinding.GetReachSpecEndName(reachSpec)) is ObjectProperty otherNodeValue &&
                reachSpec.FileRef.isUExport(otherNodeValue.Value))
            {
                return(reachSpec.FileRef.getUExport(otherNodeValue.Value));
            }

            return(null); //can't get end, or is external
        }
        public static void RandVector(PropertyCollection props, string propname, float min, float max, bool createIfMissing)
        {
            var prop = props.GetProp <StructProperty>(propname);

            if (prop == null && createIfMissing)
            {
                var propCollection = new PropertyCollection();
                propCollection.Add(new FloatProperty(0, "X"));
                propCollection.Add(new FloatProperty(0, "Y"));
                propCollection.Add(new FloatProperty(0, "Z"));
                prop = new StructProperty("Vector", propCollection, propname, true);
                props.Add(prop);
            }
            if (prop != null)
            {
                prop.GetProp <FloatProperty>("X").Value = ThreadSafeRandom.NextFloat(min, max);
                prop.GetProp <FloatProperty>("Y").Value = ThreadSafeRandom.NextFloat(min, max);
                prop.GetProp <FloatProperty>("Z").Value = ThreadSafeRandom.NextFloat(min, max);
            }
        }
示例#14
0
        public AnimSequence(ExportEntry export)
        {
            pcc    = export.FileRef;
            Export = export;
            data   = export.Data;

            Props = export.GetProperties();

            RotationCompressionFormat = Props.GetPropOrDefault <EnumProperty>("RotationCompressionFormat").Value.Instanced;
            KeyEncodingFormat         = Props.GetPropOrDefault <EnumProperty>("KeyEncodingFormat").Value.Instanced;
            bIsAdditive             = Props.GetPropOrDefault <BoolProperty>("bIsAdditive").Value;
            bNoLoopingInterpolation = Props.GetPropOrDefault <BoolProperty>("bNoLoopingInterpolation").Value;
            SequenceName            = Props.GetPropOrDefault <NameProperty>("SequenceName").Value.Instanced;
            m_pBioAnimSetData       = Props.GetPropOrDefault <ObjectProperty>("m_pBioAnimSetData").Value;
            SequenceLength          = Props.GetPropOrDefault <FloatProperty>("SequenceLength").Value;
            RateScale = Props.GetProp <FloatProperty>("RateScale")?.Value ?? 1;
            NumFrames = Props.GetPropOrDefault <IntProperty>("NumFrames").Value;
            ReadTrackOffsets(Props.GetPropOrDefault <ArrayProperty <IntProperty> >("CompressedTrackOffsets").Select(p => p.Value).ToArray());
            ReadCompressedBlob();
            Rate = NumFrames / SequenceLength * RateScale;
        }
示例#15
0
        /// <summary>
        /// Creates the reachspec connections from this pathfinding node to others.
        /// </summary>
        public override void CreateConnections(List <PathfindingNodeMaster> graphNodes)
        {
            ReachSpecs = (SharedPathfinding.GetReachspecExports(export));
            foreach (ExportEntry spec in ReachSpecs)
            {
                Pen penToUse = blackPen;
                switch (spec.ObjectName.Name)
                {
                case "SlotToSlotReachSpec":
                    penToUse = slotToSlotPen;
                    break;

                case "CoverSlipReachSpec":
                    penToUse = coverSlipPen;
                    break;

                case "SFXLadderReachSpec":
                    penToUse = sfxLadderPen;
                    break;

                case "SFXLargeBoostReachSpec":
                    penToUse = sfxLargeBoostPen;
                    break;

                case "SFXBoostReachSpec":
                    penToUse = sfxBoostPen;
                    break;

                case "SFXJumpDownReachSpec":
                    penToUse = sfxJumpDownPen;
                    break;
                }
                //Get ending
                PropertyCollection props          = spec.GetProperties();
                ExportEntry        otherEndExport = SharedPathfinding.GetReachSpecEndExport(spec, props);

                /*
                 * if (props.GetProp<StructProperty>("End") is StructProperty endProperty &&
                 *  endProperty.GetProp<ObjectProperty>(SharedPathfinding.GetReachSpecEndName(spec)) is ObjectProperty otherNodeValue)
                 * {
                 *  othernodeidx = otherNodeValue.Value;
                 * }*/

                if (otherEndExport != null)
                {
                    bool isTwoWay = false;
                    PathfindingNodeMaster othernode = graphNodes.FirstOrDefault(x => x.export == otherEndExport);
                    if (othernode != null)
                    {
                        //Check for returning reachspec for pen drawing. This is going to incur a significant performance penalty...
                        var othernodeSpecs = SharedPathfinding.GetReachspecExports(otherEndExport);
                        foreach (var path in othernodeSpecs)
                        {
                            if (SharedPathfinding.GetReachSpecEndExport(path) == export)
                            {
                                isTwoWay = true;
                                break;
                            }
                        }

                        //var
                        //    PropertyCollection otherSpecProperties = possibleIncomingSpec.GetProperties();

                        //    if (otherSpecProperties.GetProp<StructProperty>("End") is StructProperty endStruct)
                        //    {
                        //        if (endStruct.GetProp<ObjectProperty>(SharedPathfinding.GetReachSpecEndName(possibleIncomingSpec)) is ObjectProperty incomingTargetIdx)
                        //        {
                        //            if (incomingTargetIdx.Value == export.UIndex)
                        //            {
                        //                isTwoWay = true;
                        //                break;
                        //            }
                        //        }
                        //    }
                        //}

                        //if (othernode != null)
                        //{
                        var radius = props.GetProp <IntProperty>("CollisionRadius");
                        var height = props.GetProp <IntProperty>("CollisionHeight");

                        bool penCloned = false;
                        if (radius != null && height != null && (radius >= ReachSpecSize.MINIBOSS_RADIUS || height >= ReachSpecSize.MINIBOSS_HEIGHT))
                        {
                            penCloned = true;
                            penToUse  = (Pen)penToUse.Clone();

                            if (radius >= ReachSpecSize.BOSS_RADIUS && height >= ReachSpecSize.BOSS_HEIGHT)
                            {
                                penToUse.Width = 3;
                            }
                            else
                            {
                                penToUse.Width = 2;
                            }
                        }
                        if (!isTwoWay)
                        {
                            if (!penCloned)
                            {
                                penToUse  = (Pen)penToUse.Clone();
                                penCloned = true;
                            }
                            penToUse.DashStyle = DashStyle.Dash;
                        }

                        if (!penCloned)
                        {
                            //This will prevent immutable modifications later if we delete or modify reachspecs without a full
                            //graph redraw
                            penToUse  = (Pen)penToUse.Clone();
                            penCloned = true;
                        }

                        PathfindingEditorEdge edge = new PathfindingEditorEdge
                        {
                            Pen                 = penToUse,
                            EndPoints           = { [0] = this, [1] = othernode },
                            OutboundConnections = { [0] = true, [1] = isTwoWay }
                        };
                        if (!Edges.Any(x => x.DoesEdgeConnectSameNodes(edge)) && !othernode.Edges.Any(x => x.DoesEdgeConnectSameNodes(edge)))
                        {
                            //Only add edge if neither node contains this edge
                            Edges.Add(edge);
                            othernode.Edges.Add(edge);
                            g.edgeLayer.AddChild(edge);
                        }
                    }
                }
            }
        }
示例#16
0
        public static string Replace(this Texture2D t2d, Image image, PropertyCollection props, string fileSourcePath = null, string forcedTFCName = null)
        {
            string      errors       = "";
            var         textureCache = forcedTFCName ?? t2d.GetTopMip().TextureCacheName;
            string      fmt          = t2d.TextureFormat;
            PixelFormat pixelFormat  = Image.getPixelFormatType(fmt);

            t2d.RemoveEmptyMipsFromMipList();

            // Not sure what this does?
            // Remove all but one mip?
            //if (Export.Game == MEGame.ME1 && texture.mipMapsList.Count < 6)
            //{
            //    for (int i = texture.mipMapsList.Count - 1; i != 0; i--)
            //        texture.mipMapsList.RemoveAt(i);
            //}
            PixelFormat newPixelFormat = pixelFormat;

            //Changing Texture Type. Not sure what this is, exactly.
            //if (mod.markConvert)
            //    newPixelFormat = changeTextureType(pixelFormat, image.pixelFormat, ref package, ref texture);


            if (!image.checkDDSHaveAllMipmaps() || t2d.Mips.Count > 1 && image.mipMaps.Count() <= 1 || image.pixelFormat != newPixelFormat)
            //(!mod.markConvert && image.pixelFormat != pixelFormat))
            {
                bool dxt1HasAlpha  = false;
                byte dxt1Threshold = 128;
                if (pixelFormat == PixelFormat.DXT1 && props.GetProp <EnumProperty>("CompressionSettings") is EnumProperty compressionSettings && compressionSettings.Value.Name == "TC_OneBitAlpha")
                {
                    dxt1HasAlpha = true;
                    if (image.pixelFormat == PixelFormat.ARGB ||
                        image.pixelFormat == PixelFormat.DXT3 ||
                        image.pixelFormat == PixelFormat.DXT5)
                    {
                        errors += "Warning: Texture was converted from full alpha to binary alpha." + Environment.NewLine;
                    }
                }

                //Generate lower mips
                image.correctMips(newPixelFormat, dxt1HasAlpha, dxt1Threshold);
            }

            if (t2d.Mips.Count == 1)
            {
                var topMip = image.mipMaps[0];
                image.mipMaps.Clear();
                image.mipMaps.Add(topMip);
            }
            else
            {
                // remove lower mipmaps from source image which not exist in game data
                //Not sure what this does since we just generated most of these mips
                for (int t = 0; t < image.mipMaps.Count(); t++)
                {
                    if (image.mipMaps[t].origWidth <= t2d.Mips[0].width &&
                        image.mipMaps[t].origHeight <= t2d.Mips[0].height &&
                        t2d.Mips.Count > 1)
                    {
                        if (!t2d.Mips.Exists(m => m.width == image.mipMaps[t].origWidth && m.height == image.mipMaps[t].origHeight))
                        {
                            image.mipMaps.RemoveAt(t--);
                        }
                    }
                }

                // put empty mips if missing
                for (int t = 0; t < t2d.Mips.Count; t++)
                {
                    if (t2d.Mips[t].width <= image.mipMaps[0].origWidth &&
                        t2d.Mips[t].height <= image.mipMaps[0].origHeight)
                    {
                        if (!image.mipMaps.Exists(m => m.origWidth == t2d.Mips[t].width && m.origHeight == t2d.Mips[t].height))
                        {
                            MipMap mipmap = new MipMap(t2d.Mips[t].width, t2d.Mips[t].height, pixelFormat);
                            image.mipMaps.Add(mipmap);
                        }
                    }
                }
            }

            //if (!texture.properties.exists("LODGroup"))
            //    texture.properties.setByteValue("LODGroup", "TEXTUREGROUP_Character", "TextureGroup", 1025);
            List <byte[]> compressedMips = new List <byte[]>();

            for (int m = 0; m < image.mipMaps.Count(); m++)
            {
                if (t2d.Export.Game == MEGame.ME2)
                {
                    compressedMips.Add(TextureCompression.CompressTexture(image.mipMaps[m].data, StorageTypes.extLZO)); //LZO
                }
                else
                {
                    compressedMips.Add(TextureCompression.CompressTexture(image.mipMaps[m].data, StorageTypes.extZlib)); //ZLib
                }
            }

            List <Texture2DMipInfo> mipmaps = new List <Texture2DMipInfo>();

            for (int m = 0; m < image.mipMaps.Count(); m++)
            {
                Texture2DMipInfo mipmap = new Texture2DMipInfo();
                mipmap.Export           = t2d.Export;
                mipmap.width            = image.mipMaps[m].origWidth;
                mipmap.height           = image.mipMaps[m].origHeight;
                mipmap.TextureCacheName = textureCache;
                if (t2d.Mips.Exists(x => x.width == mipmap.width && x.height == mipmap.height))
                {
                    var oldMip = t2d.Mips.First(x => x.width == mipmap.width && x.height == mipmap.height);
                    mipmap.storageType = oldMip.storageType;
                }
                else
                {
                    mipmap.storageType = t2d.Mips[0].storageType;
                    if (t2d.Mips.Count() > 1)
                    {
                        //Will implement later. ME3Explorer won't support global relinking, that's MEM's job.
                        //if (Export.Game == MEGame.ME1 && matched.linkToMaster == -1)
                        //{
                        //    if (mipmap.storageType == StorageTypes.pccUnc)
                        //    {
                        //        mipmap.storageType = StorageTypes.pccLZO;
                        //    }
                        //}
                        //else if (Export.Game == MEGame.ME1 && matched.linkToMaster != -1)
                        //{
                        //    if (mipmap.storageType == StorageTypes.pccUnc ||
                        //        mipmap.storageType == StorageTypes.pccLZO ||
                        //        mipmap.storageType == StorageTypes.pccZlib)
                        //    {
                        //        mipmap.storageType = StorageTypes.extLZO;
                        //    }
                        //}
                        //else
                    }
                }

                //ME2,ME3: Force compression type (not implemented yet)
                if (t2d.Export.Game == MEGame.ME3)
                {
                    if (mipmap.storageType == StorageTypes.extLZO) //ME3 LZO -> ZLIB
                    {
                        mipmap.storageType = StorageTypes.extZlib;
                    }
                    if (mipmap.storageType == StorageTypes.pccLZO) //ME3 PCC LZO -> PCCZLIB
                    {
                        mipmap.storageType = StorageTypes.pccZlib;
                    }
                    if (mipmap.storageType == StorageTypes.extUnc) //ME3 Uncomp -> ZLib
                    {
                        mipmap.storageType = StorageTypes.extZlib;
                    }
                    //Leave here for future. WE might need this after dealing with double compression
                    //if (mipmap.storageType == StorageTypes.pccUnc && mipmap.width > 32) //ME3 Uncomp -> ZLib
                    //    mipmap.storageType = StorageTypes.pccZlib;
                    if (mipmap.storageType == StorageTypes.pccUnc && m < image.mipMaps.Count() - 6 && textureCache != null) //Moving texture to store externally.
                    {
                        mipmap.storageType = StorageTypes.extZlib;
                    }
                }
                else if (t2d.Export.Game == MEGame.ME2)
                {
                    if (mipmap.storageType == StorageTypes.extZlib) //ME2 ZLib -> LZO
                    {
                        mipmap.storageType = StorageTypes.extLZO;
                    }
                    if (mipmap.storageType == StorageTypes.pccZlib) //M2 ZLib -> LZO
                    {
                        mipmap.storageType = StorageTypes.pccLZO;
                    }
                    if (mipmap.storageType == StorageTypes.extUnc) //ME2 Uncomp -> LZO
                    {
                        mipmap.storageType = StorageTypes.extLZO;
                    }
                    //Leave here for future. We might neable this after dealing with double compression
                    //if (mipmap.storageType == StorageTypes.pccUnc && mipmap.width > 32) //ME2 Uncomp -> LZO
                    //    mipmap.storageType = StorageTypes.pccLZO;
                    if (mipmap.storageType == StorageTypes.pccUnc && m < image.mipMaps.Count() - 6 && textureCache != null) //Moving texture to store externally. make sure bottom 6 are pcc stored
                    {
                        mipmap.storageType = StorageTypes.extLZO;
                    }
                }


                //Investigate. this has something to do with archive storage types
                //if (mod.arcTexture != null)
                //{
                //    if (mod.arcTexture[m].storageType != mipmap.storageType)
                //    {
                //        mod.arcTexture = null;
                //    }
                //}

                mipmap.width  = image.mipMaps[m].width;
                mipmap.height = image.mipMaps[m].height;
                mipmaps.Add(mipmap);
                if (t2d.Mips.Count() == 1)
                {
                    break;
                }
            }

            #region MEM code comments. Should probably leave for reference

            //if (texture.properties.exists("TextureFileCacheName"))
            //{
            //    string archive = texture.properties.getProperty("TextureFileCacheName").valueName;
            //    if (mod.arcTfcDLC && mod.arcTfcName != archive)
            //        mod.arcTexture = null;

            //    if (mod.arcTexture == null)
            //    {
            //        archiveFile = Path.Combine(GameData.MainData, archive + ".tfc");
            //        if (matched.path.ToLowerInvariant().Contains("\\dlc"))
            //        {
            //            mod.arcTfcDLC = true;
            //            string DLCArchiveFile = Path.Combine(Path.GetDirectoryName(GameData.GamePath + matched.path), archive + ".tfc");
            //            if (File.Exists(DLCArchiveFile))
            //                archiveFile = DLCArchiveFile;
            //            else if (!File.Exists(archiveFile))
            //            {
            //                List<string> files = Directory.GetFiles(GameData.bioGamePath, archive + ".tfc",
            //                    SearchOption.AllDirectories).Where(item => item.EndsWith(".tfc", StringComparison.OrdinalIgnoreCase)).ToList();
            //                if (files.Count == 1)
            //                    archiveFile = files[0];
            //                else if (files.Count == 0)
            //                {
            //                    using (FileStream fs = new FileStream(DLCArchiveFile, FileMode.CreateNew, FileAccess.Write))
            //                    {
            //                        fs.WriteFromBuffer(texture.properties.getProperty("TFCFileGuid").valueStruct);
            //                    }
            //                    archiveFile = DLCArchiveFile;
            //                    newTfcFile = true;
            //                }
            //                else
            //                    throw new Exception("More instnces of TFC file: " + archive + ".tfc");
            //            }
            //        }
            //        else
            //        {
            //            mod.arcTfcDLC = false;
            //        }

            //        // check if texture fit in old space
            //        for (int mip = 0; mip < image.mipMaps.Count(); mip++)
            //        {
            //            Texture.MipMap testMipmap = new Texture.MipMap();
            //            testMipmap.width = image.mipMaps[mip].origWidth;
            //            testMipmap.height = image.mipMaps[mip].origHeight;
            //            if (ExistMipmap(testMipmap.width, testMipmap.height))
            //                testMipmap.storageType = texture.getMipmap(testMipmap.width, testMipmap.height).storageType;
            //            else
            //            {
            //                oldSpace = false;
            //                break;
            //            }

            //            if (testMipmap.storageType == StorageTypes.extZlib ||
            //                testMipmap.storageType == StorageTypes.extLZO)
            //            {
            //                Texture.MipMap oldTestMipmap = texture.getMipmap(testMipmap.width, testMipmap.height);
            //                if (mod.cacheCprMipmaps[mip].Length > oldTestMipmap.compressedSize)
            //                {
            //                    oldSpace = false;
            //                    break;
            //                }
            //            }
            //            if (texture.mipMapsList.Count() == 1)
            //                break;
            //        }

            //        long fileLength = new FileInfo(archiveFile).Length;
            //        if (!oldSpace && fileLength + 0x5000000 > 0x80000000)
            //        {
            //            archiveFile = "";
            //            foreach (TFCTexture newGuid in guids)
            //            {
            //                archiveFile = Path.Combine(GameData.MainData, newGuid.name + ".tfc");
            //                if (!File.Exists(archiveFile))
            //                {
            //                    texture.properties.setNameValue("TextureFileCacheName", newGuid.name);
            //                    texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid);
            //                    using (FileStream fs = new FileStream(archiveFile, FileMode.CreateNew, FileAccess.Write))
            //                    {
            //                        fs.WriteFromBuffer(newGuid.guid);
            //                    }
            //                    newTfcFile = true;
            //                    break;
            //                }
            //                else
            //                {
            //                    fileLength = new FileInfo(archiveFile).Length;
            //                    if (fileLength + 0x5000000 < 0x80000000)
            //                    {
            //                        texture.properties.setNameValue("TextureFileCacheName", newGuid.name);
            //                        texture.properties.setStructValue("TFCFileGuid", "Guid", newGuid.guid);
            //                        break;
            //                    }
            //                }
            //                archiveFile = "";
            //            }
            //            if (archiveFile == "")
            //                throw new Exception("No free TFC texture file!");
            //        }
            //    }
            //    else
            //    {
            //        texture.properties.setNameValue("TextureFileCacheName", mod.arcTfcName);
            //        texture.properties.setStructValue("TFCFileGuid", "Guid", mod.arcTfcGuid);
            //    }
            //}

            #endregion

            int allextmipssize = 0;

            for (int m = 0; m < image.mipMaps.Count(); m++)
            {
                Texture2DMipInfo x = mipmaps[m];
                var compsize       = image.mipMaps[m].data.Length;

                if (x.storageType == StorageTypes.extZlib ||
                    x.storageType == StorageTypes.extLZO ||
                    x.storageType == StorageTypes.extUnc)
                {
                    allextmipssize += compsize; //compsize on Unc textures is same as LZO/ZLib
                }
            }
            //todo: check to make sure TFC will not be larger than 2GiB
            Guid tfcGuid       = Guid.NewGuid(); //make new guid as storage
            bool locallyStored = mipmaps[0].storageType == StorageTypes.pccUnc || mipmaps[0].storageType == StorageTypes.pccZlib || mipmaps[0].storageType == StorageTypes.pccLZO;
            for (int m = 0; m < image.mipMaps.Count(); m++)
            {
                Texture2DMipInfo mipmap = mipmaps[m];
                //if (mipmap.width > 32)
                //{
                //    if (mipmap.storageType == StorageTypes.pccUnc)
                //    {
                //        mipmap.storageType = Export.Game == MEGame.ME2 ? StorageTypes.pccLZO : StorageTypes.pccZlib;
                //    }
                //    if (mipmap.storageType == StorageTypes.extUnc)
                //    {
                //        mipmap.storageType = Export.Game == MEGame.ME2 ? StorageTypes.extLZO : StorageTypes.extZlib;
                //    }
                //}

                mipmap.uncompressedSize = image.mipMaps[m].data.Length;
                if (t2d.Export.Game == MEGame.ME1)
                {
                    if (mipmap.storageType == StorageTypes.pccLZO ||
                        mipmap.storageType == StorageTypes.pccZlib)
                    {
                        mipmap.Mip            = compressedMips[m];
                        mipmap.compressedSize = mipmap.Mip.Length;
                    }
                    else if (mipmap.storageType == StorageTypes.pccUnc)
                    {
                        mipmap.compressedSize = mipmap.uncompressedSize;
                        mipmap.Mip            = image.mipMaps[m].data;
                    }
                    else
                    {
                        throw new Exception("Unknown mip storage type!");
                    }
                }
                else
                {
                    if (mipmap.storageType == StorageTypes.extZlib ||
                        mipmap.storageType == StorageTypes.extLZO)
                    {
                        if (compressedMips.Count != image.mipMaps.Count())
                        {
                            throw new Exception("Amount of compressed mips does not match number of mips of incoming image!");
                        }
                        mipmap.Mip            = compressedMips[m];
                        mipmap.compressedSize = mipmap.Mip.Length;
                    }


                    if (mipmap.storageType == StorageTypes.pccUnc ||
                        mipmap.storageType == StorageTypes.extUnc)
                    {
                        mipmap.compressedSize = mipmap.uncompressedSize;
                        mipmap.Mip            = image.mipMaps[m].data;
                    }

                    if (mipmap.storageType == StorageTypes.pccLZO || mipmap.storageType == StorageTypes.pccZlib)
                    {
                        mipmap.Mip            = compressedMips[m];
                        mipmap.compressedSize = mipmap.Mip.Length;
                    }

                    if (mipmap.storageType == StorageTypes.extZlib ||
                        mipmap.storageType == StorageTypes.extLZO ||
                        mipmap.storageType == StorageTypes.extUnc)
                    {
                        if (!string.IsNullOrEmpty(mipmap.TextureCacheName) && mipmap.Export.Game != MEGame.ME1)
                        {
                            //Check local dir
                            string tfcarchive            = mipmap.TextureCacheName + ".tfc";
                            var    localDirectoryTFCPath = Path.Combine(Path.GetDirectoryName(mipmap.Export.FileRef.FilePath), tfcarchive);
                            if (File.Exists(localDirectoryTFCPath))
                            {
                                try
                                {
                                    using (FileStream fs = new FileStream(localDirectoryTFCPath, FileMode.Open, FileAccess.ReadWrite))
                                    {
                                        tfcGuid = fs.ReadGuid();
                                        fs.Seek(0, SeekOrigin.End);
                                        mipmap.externalOffset = (int)fs.Position;
                                        fs.Write(mipmap.Mip, 0, mipmap.compressedSize);
                                    }
                                }
                                catch (Exception e)
                                {
                                    throw new Exception("Problem appending to TFC file " + tfcarchive + ": " + e.Message);
                                }
                                continue;
                            }

                            //Check game
                            var gameFiles = MELoadedFiles.GetFilesLoadedInGame(mipmap.Export.Game, includeTFCs: true);
                            if (gameFiles.TryGetValue(tfcarchive, out string archiveFile))
                            {
                                try
                                {
                                    using (FileStream fs = new FileStream(archiveFile, FileMode.Open, FileAccess.ReadWrite))
                                    {
                                        tfcGuid = fs.ReadGuid();
                                        fs.Seek(0, SeekOrigin.End);
                                        mipmap.externalOffset = (int)fs.Position;
                                        fs.Write(mipmap.Mip, 0, mipmap.compressedSize);
                                    }
                                }
                                catch (Exception e)
                                {
                                    throw new Exception("Problem appending to TFC file " + archiveFile + ": " + e.Message);
                                }
                                continue;
                            }


                            //Cache not found. Make new TFC
                            try
                            {
                                using (FileStream fs = new FileStream(localDirectoryTFCPath, FileMode.OpenOrCreate, FileAccess.Write))
                                {
                                    fs.WriteGuid(tfcGuid);
                                    mipmap.externalOffset = (int)fs.Position;
                                    fs.Write(mipmap.Mip, 0, mipmap.compressedSize);
                                }
                            }
                            catch (Exception e)
                            {
                                throw new Exception("Problem creating new TFC file " + tfcarchive + ": " + e.Message);
                            }
                            continue;
                        }
                    }
                }
                mipmaps[m] = mipmap;
                if (t2d.Mips.Count() == 1)
                {
                    break;
                }
            }

            t2d.ReplaceMips(mipmaps);

            //Set properties


            // The bottom 6 mips are apparently always pcc stored. If there is less than 6 mips, set neverstream to true, which tells game
            // and toolset to never look into archives for mips.
            //if (Export.Game == MEGame.ME2 || Export.Game == MEGame.ME3)
            //{
            //    if (texture.properties.exists("TextureFileCacheName"))
            //    {
            //        if (texture.mipMapsList.Count < 6)
            //        {
            //            mipmap.storageType = StorageTypes.pccUnc;
            //            texture.properties.setBoolValue("NeverStream", true);
            //        }
            //        else
            //        {
            //            if (Export.Game == MEGame.ME2)
            //                mipmap.storageType = StorageTypes.extLZO;
            //            else
            //                mipmap.storageType = StorageTypes.extZlib;
            //        }
            //    }
            //}

            var hasNeverStream = props.GetProp <BoolProperty>("NeverStream") != null;
            if (locallyStored)
            {
                // Rules for default neverstream
                // 1. Must be Package Stored
                // 2. Must have at least 6 not empty mips
                if (mipmaps.Count >= 6)
                {
                    props.AddOrReplaceProp(new BoolProperty(true, "NeverStream"));
                }
                // Side case: NeverStream property was already set, we should respect the value
                // But won't that always be set here?
                // Is there a time where we should remove NeverStream? I can't see any logical way
                // neverstream would be here
            }

            if (mipmaps.Count < 6)
            {
                props.RemoveNamedProperty("NeverStream");
            }

            if (!locallyStored)
            {
                props.AddOrReplaceProp(tfcGuid.ToGuidStructProp("TFCFileGuid"));
                if (mipmaps[0].storageType == StorageTypes.extLZO || mipmaps[0].storageType == StorageTypes.extUnc || mipmaps[0].storageType == StorageTypes.extZlib)
                {
                    //Requires texture cache name
                    props.AddOrReplaceProp(new NameProperty(textureCache, "TextureFileCacheName"));
                }
                else
                {
                    //Should not have texture cache name
                    var cacheProp = props.GetProp <NameProperty>("TextureFileCacheName");
                    if (cacheProp != null)
                    {
                        props.Remove(cacheProp);
                    }
                }
            }
            else
            {
                props.RemoveNamedProperty("TFCFileGuid");
            }

            props.AddOrReplaceProp(new IntProperty(t2d.Mips.First().width, "SizeX"));
            props.AddOrReplaceProp(new IntProperty(t2d.Mips.First().height, "SizeY"));
            if (t2d.Export.Game < MEGame.ME3 && fileSourcePath != null)
            {
                props.AddOrReplaceProp(new StrProperty(fileSourcePath, "SourceFilePath"));
                props.AddOrReplaceProp(new StrProperty(File.GetLastWriteTimeUtc(fileSourcePath).ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture), "SourceFileTimestamp"));
            }

            var mipTailIdx = props.GetProp <IntProperty>("MipTailBaseIdx");
            if (mipTailIdx != null)
            {
                mipTailIdx.Value = t2d.Mips.Count - 1;
            }

            EndianReader mem = new EndianReader(new MemoryStream())
            {
                Endian = t2d.Export.FileRef.Endian
            };
            props.WriteTo(mem.Writer, t2d.Export.FileRef);
            mem.Position = 0;
            var test      = PropertyCollection.ReadProps(t2d.Export, mem.BaseStream, "Texture2D", true, true); //do not set properties as this may interfere with some other code. may change later.
            int propStart = t2d.Export.GetPropertyStart();
            var pos       = mem.Position;
            mem.Position = 0;
            byte[] propData = mem.ToArray();
            if (t2d.Export.Game == MEGame.ME3)
            {
                t2d.Export.Data = t2d.Export.Data.Take(propStart).Concat(propData).Concat(t2d.SerializeNewData()).ToArray();
            }
            else
            {
                var array    = t2d.Export.Data.Take(propStart).Concat(propData).ToArray();
                var testdata = new MemoryStream(array);
                var test2    = PropertyCollection.ReadProps(t2d.Export, testdata, "Texture2D", true, true, t2d.Export); //do not set properties as this may interfere with some other code. may change later.
                                                                                                                        //ME2 post-data is this right?
                t2d.Export.Data = t2d.Export.Data.Take(propStart).Concat(propData).Concat(t2d.SerializeNewData()).ToArray();
            }

            //using (MemoryStream newData = new MemoryStream())
            //{
            //    newData.WriteFromBuffer(texture.properties.toArray());
            //    newData.WriteFromBuffer(texture.toArray(0, false)); // filled later
            //    package.setExportData(matched.exportID, newData.ToArray());
            //}

            //using (MemoryStream newData = new MemoryStream())
            //{
            //    newData.WriteFromBuffer(texture.properties.toArray());
            //    newData.WriteFromBuffer(texture.toArray(package.exportsTable[matched.exportID].dataOffset + (uint)newData.Position));
            //    package.setExportData(matched.exportID, newData.ToArray());
            //}

            //Since this is single replacement, we don't want to relink to master
            //We want to ensure names are different though, will have to implement into UI
            //if (Export.Game == MEGame.ME1)
            //{
            //    if (matched.linkToMaster == -1)
            //        mod.masterTextures.Add(texture.mipMapsList, entryMap.listIndex);
            //}
            //else
            //{
            //    if (triggerCacheArc)
            //    {
            //        mod.arcTexture = texture.mipMapsList;
            //        mod.arcTfcGuid = texture.properties.getProperty("TFCFileGuid").valueStruct;
            //        mod.arcTfcName = texture.properties.getProperty("TextureFileCacheName").valueName;
            //    }
            //}


            return(errors);
        }
示例#17
0
        protected PointF[] get3DBrushShape()
        {
            try
            {
                PropertyCollection props = export.GetProperties();
                float xScalar = 1;
                float yScalar = 1;
                //float zScalar = 1;

                var drawScale = props.GetProp<FloatProperty>("DrawScale");
                var drawScale3d = props.GetProp<StructProperty>("DrawScale3D");
                if (drawScale != null)
                {
                    xScalar = yScalar = drawScale.Value;
                }
                if (drawScale3d != null)
                {
                    xScalar *= drawScale3d.GetProp<FloatProperty>("X").Value;
                    yScalar *= drawScale3d.GetProp<FloatProperty>("Y").Value;
                }

                var brushComponent = props.GetProp<ObjectProperty>("BrushComponent");
                if (brushComponent == null)
                {
                    return null;
                }
                IExportEntry brush = export.FileRef.getExport(brushComponent.Value - 1);
                List<PointF> graphVertices = new List<PointF>();
                List<Vector3> brushVertices = new List<Vector3>();
                PropertyCollection brushProps = brush.GetProperties();
                var brushAggGeom = brushProps.GetProp<StructProperty>("BrushAggGeom");
                if (brushAggGeom == null)
                {
                    return null;
                }
                var convexList = brushAggGeom.GetProp<ArrayProperty<StructProperty>>("ConvexElems");

                //Vertices
                var verticiesList = convexList[0].Properties.GetProp<ArrayProperty<StructProperty>>("VertexData");
                foreach (StructProperty vertex in verticiesList)
                {
                    Vector3 point = new Vector3();
                    point.X = vertex.GetProp<FloatProperty>("X") * xScalar;
                    point.Y = vertex.GetProp<FloatProperty>("Y") * yScalar;
                    point.Z = vertex.GetProp<FloatProperty>("Z");
                    brushVertices.Add(point);
                }

                //FaceTris
                var faceTriData = convexList[0].Properties.GetProp<ArrayProperty<IntProperty>>("FaceTriData");
                Vector3 previousVertex = new Vector3();
                float prevX = float.MinValue;
                float prevY = float.MinValue;
                foreach (IntProperty triPoint in faceTriData)
                {
                    Vector3 vertex = brushVertices[triPoint];
                    if (vertex.X == prevX && vertex.Y == prevY)
                    {
                        continue; //Z is on the difference
                    }

                    float x = vertex.X;
                    float y = vertex.Y;

                    prevX = x;
                    prevY = y;
                    PointF graphPoint = new PointF(x, y);
                    graphVertices.Add(graphPoint);
                }
                return graphVertices.ToArray();
            } catch (Exception)
            {
                return null;
            }
        }
示例#18
0
        /// <summary>
        /// Creates the reachspec connections from this pathfinding node to others.
        /// </summary>
        public override void CreateConnections(ref List <PathfindingNodeMaster> Objects)
        {
            var outLinksProp = export.GetProperty <ArrayProperty <ObjectProperty> >("PathList");

            if (outLinksProp != null)
            {
                foreach (var prop in outLinksProp)
                {
                    int reachspecexport = prop.Value;
                    ReachSpecs.Add(pcc.Exports[reachspecexport - 1]);
                }

                foreach (IExportEntry spec in ReachSpecs)
                {
                    Pen penToUse = halfReachSpecPen;
                    switch (spec.ObjectName)
                    {
                    case "SlotToSlotReachSpec":
                        penToUse = slotToSlotPen;
                        break;

                    case "SFXLadderReachSpec":
                        penToUse = sfxLadderPen;
                        break;

                    case "SFXLargeBoostReachSpec":
                        penToUse = sfxLargeBoostPen;
                        break;

                    case "SFXBoostReachSpec":
                        penToUse = sfxBoostPen;
                        break;

                    case "SFXJumpDownReachSpec":
                        penToUse = sfxJumpDownPen;
                        break;
                    }
                    //Get ending
                    PNode othernode          = null;
                    int   othernodeidx       = 0;
                    PropertyCollection props = spec.GetProperties();
                    foreach (var prop in props)
                    {
                        if (prop.Name == "End")
                        {
                            PropertyCollection reachspecprops = (prop as StructProperty).Properties;
                            foreach (var rprop in reachspecprops)
                            {
                                if (rprop.Name == "Actor")
                                {
                                    othernodeidx = (rprop as ObjectProperty).Value;
                                    break;
                                }
                            }
                        }
                    }

                    if (othernodeidx != 0)
                    {
                        foreach (PathfindingNodeMaster node in Objects)
                        {
                            if (node.export.UIndex == othernodeidx)
                            {
                                othernode = node;

                                //Check for returning reachspec for pen drawing. This is going to incur a significant performance penalty...
                                IExportEntry otherNode         = node.export;
                                var          otherNodePathList = otherNode.GetProperty <ArrayProperty <ObjectProperty> >("PathList");
                                if (otherNodePathList != null)
                                {
                                    bool keepParsing = true;
                                    foreach (var path in otherNodePathList)
                                    {
                                        int                reachspecexport      = path.Value;
                                        IExportEntry       possibleIncomingSpec = pcc.Exports[reachspecexport - 1];
                                        PropertyCollection otherSpecProperties  = possibleIncomingSpec.GetProperties();
                                        foreach (var otherSpecProp in otherSpecProperties)
                                        {
                                            if (otherSpecProp.Name == "End")
                                            {
                                                PropertyCollection reachspecprops = (otherSpecProp as StructProperty).Properties;
                                                foreach (var rprop in reachspecprops)
                                                {
                                                    if (rprop.Name == "Actor")
                                                    {
                                                        othernodeidx = (rprop as ObjectProperty).Value;
                                                        if (othernodeidx == export.UIndex)
                                                        {
                                                            keepParsing = false;
                                                            if (penToUse == halfReachSpecPen)
                                                            {
                                                                penToUse = blackPen;
                                                            }
                                                            break;
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        if (!keepParsing)
                                        {
                                            break;
                                        }
                                    }
                                    break;
                                }
                            }
                        }
                        if (othernode != null)
                        {
                            IntProperty radius = props.GetProp <IntProperty>("CollisionRadius");
                            IntProperty height = props.GetProp <IntProperty>("CollisionHeight");

                            if (radius != null && height != null && (radius >= PathfindingNodeInfoPanel.MINIBOSS_RADIUS || height >= PathfindingNodeInfoPanel.MINIBOSS_HEIGHT))
                            {
                                penToUse = (Pen)penToUse.Clone();
                                if (radius >= PathfindingNodeInfoPanel.BOSS_RADIUS && height >= PathfindingNodeInfoPanel.BOSS_HEIGHT)
                                {
                                    penToUse.Width = 3;
                                }
                                else
                                {
                                    penToUse.Width = 2;
                                }
                            }

                            PPath edge = new PPath();
                            edge.Pen = penToUse;
                            ((ArrayList)Tag).Add(edge);
                            ((ArrayList)othernode.Tag).Add(edge);
                            edge.Tag = new ArrayList();
                            ((ArrayList)edge.Tag).Add(this);
                            ((ArrayList)edge.Tag).Add(othernode);

                            g.edgeLayer.AddChild(edge);
                        }
                    }
                }
            }
        }
示例#19
0
 /// <summary>
 /// Changes a single output link to a new target.
 /// </summary>
 /// <param name="export">The export properties list to operate on</param>
 /// <param name="outputLinkIndex">The index of the item in 'OutputLinks'</param>
 /// <param name="linksIndex">The index of the item in the Links array</param>
 /// <param name="newTarget">The UIndex of the new target</param>
 public static void ChangeOutlink(PropertyCollection props, int outputLinkIndex, int linksIndex, int newTarget)
 {
     props.GetProp <ArrayProperty <StructProperty> >("OutputLinks")[outputLinkIndex].GetProp <ArrayProperty <StructProperty> >("Links")[linksIndex].GetProp <ObjectProperty>("LinkedOp").Value = newTarget;
 }
        public static PropertyCollection GetSequenceObjectDefaults(IMEPackage pcc, ClassInfo info)
        {
            MEGame             game     = pcc.Game;
            PropertyCollection defaults = new PropertyCollection();

            if (info.ClassName == "Sequence")
            {
                defaults.Add(new ArrayProperty <ObjectProperty>("SequenceObjects"));
            }
            else if (!info.IsA(SequenceVariableName, game))
            {
                ArrayProperty <StructProperty> varLinksProp   = null;
                ArrayProperty <StructProperty> outLinksProp   = null;
                ArrayProperty <StructProperty> eventLinksProp = null;
                ArrayProperty <StructProperty> inLinksProp    = null;
                Dictionary <string, ClassInfo> classes        = UnrealObjectInfo.GetClasses(game);
                try
                {
                    ClassInfo classInfo = info;
                    while (classInfo != null && (varLinksProp is null || outLinksProp is null || eventLinksProp is null || game == MEGame.ME1 && inLinksProp is null))
                    {
                        string filepath   = Path.Combine(MEDirectories.GetBioGamePath(game), classInfo.pccPath);
                        Stream loadStream = null;
                        if (File.Exists(classInfo.pccPath))
                        {
                            loadStream = new MemoryStream(File.ReadAllBytes(classInfo.pccPath));
                        }
                        else if (classInfo.pccPath == UnrealObjectInfo.Me3ExplorerCustomNativeAdditionsName)
                        {
                            loadStream = Utilities.GetCustomAppResourceStream(game);
                        }
                        else if (File.Exists(filepath))
                        {
                            loadStream = new MemoryStream(File.ReadAllBytes(filepath));
                        }
                        else if (game == MEGame.ME1)
                        {
                            filepath = Path.Combine(ME1Directory.DefaultGamePath, classInfo.pccPath); //for files from ME1 DLC
                            if (File.Exists(filepath))
                            {
                                loadStream = new MemoryStream(File.ReadAllBytes(filepath));
                            }
                        }
                        if (loadStream != null)
                        {
                            using IMEPackage importPCC = MEPackageHandler.OpenMEPackageFromStream(loadStream);
                            ExportEntry classExport   = importPCC.GetUExport(classInfo.exportIndex);
                            UClass      classBin      = ObjectBinary.From <UClass>(classExport);
                            ExportEntry classDefaults = importPCC.GetUExport(classBin.Defaults);

                            foreach (var prop in classDefaults.GetProperties())
                            {
                                if (varLinksProp == null && prop.Name == "VariableLinks" && prop is ArrayProperty <StructProperty> vlp)
                                {
                                    varLinksProp = vlp;
                                    //relink ExpectedType
                                    foreach (StructProperty varLink in varLinksProp)
                                    {
                                        if (varLink.GetProp <ObjectProperty>("ExpectedType") is ObjectProperty expectedTypeProp &&
                                            importPCC.TryGetEntry(expectedTypeProp.Value, out IEntry expectedVar) &&
                                            EntryImporterExtended.EnsureClassIsInFile(pcc, expectedVar.ObjectName) is IEntry portedExpectedVar)
                                        {
                                            expectedTypeProp.Value = portedExpectedVar.UIndex;
                                        }
                                    }
                                }
                                if (outLinksProp == null && prop.Name == "OutputLinks" && prop is ArrayProperty <StructProperty> olp)
                                {
                                    outLinksProp = olp;
                                }

                                if (eventLinksProp == null && prop.Name == "EventLinks" && prop is ArrayProperty <StructProperty> elp)
                                {
                                    eventLinksProp = elp;
                                    //relink ExpectedType
                                    foreach (StructProperty eventLink in eventLinksProp)
                                    {
                                        if (eventLink.GetProp <ObjectProperty>("ExpectedType") is ObjectProperty expectedTypeProp &&
                                            importPCC.TryGetEntry(expectedTypeProp.Value, out IEntry expectedVar) &&
                                            EntryImporterExtended.EnsureClassIsInFile(pcc, expectedVar.ObjectName) is IEntry portedExpectedVar)
                                        {
                                            expectedTypeProp.Value = portedExpectedVar.UIndex;
                                        }
                                    }
                                }

                                if (game == MEGame.ME1 && inLinksProp is null && prop.Name == "InputLinks" && prop is ArrayProperty <StructProperty> ilp)
                                {
                                    inLinksProp = ilp;
                                }
                            }
                        }
                        classes.TryGetValue(classInfo.baseClass, out classInfo);
                    }
                }
                catch
                {
                    // ignored
                }
                if (varLinksProp != null)
                {
                    defaults.Add(varLinksProp);
                }
                if (outLinksProp != null)
                {
                    defaults.Add(outLinksProp);
                }
                if (eventLinksProp != null)
                {
                    defaults.Add(eventLinksProp);
                }
                if (inLinksProp != null)
                {
                    defaults.Add(inLinksProp);
                }

                //remove links if empty
                if (defaults.GetProp <ArrayProperty <StructProperty> >("OutputLinks") is { } outLinks&& outLinks.IsEmpty())
                {
                    defaults.Remove(outLinks);
                }
                if (defaults.GetProp <ArrayProperty <StructProperty> >("VariableLinks") is { } varLinks&& varLinks.IsEmpty())
                {
                    defaults.Remove(varLinks);
                }
                if (defaults.GetProp <ArrayProperty <StructProperty> >("EventLinks") is { } eventLinks&& eventLinks.IsEmpty())
                {
                    defaults.Remove(eventLinks);
                }
                if (defaults.GetProp <ArrayProperty <StructProperty> >("InputLinks") is { } inputLinks&& inputLinks.IsEmpty())
                {
                    defaults.Remove(inputLinks);
                }
            }

            int objInstanceVersion = UnrealObjectInfo.getSequenceObjectInfo(game, info.ClassName)?.ObjInstanceVersion ?? 1;

            defaults.Add(new IntProperty(objInstanceVersion, "ObjInstanceVersion"));

            return(defaults);
        }