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; * }*/ }
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"); }
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)); }
/// <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; } }
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); }
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()); } }
//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)); }
//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()); } }
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); } }
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); } }
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; }
/// <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); } } } } }
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); }
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; } }
/// <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); } } } } }
/// <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); }