Beispiel #1
0
        private static void ConfigureLogger()
        {
            var folder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "JWLMerge\\Logs");

            try
            {
                if (!Directory.Exists(folder))
                {
                    Directory.CreateDirectory(folder);
                }

                Log.Logger = new LoggerConfiguration()
                             .MinimumLevel.Debug()
                             .WriteTo.File(Path.Combine(folder, "log.txt"), rollingInterval: RollingInterval.Day, retainedFileCountLimit: 28)
                             .CreateLogger();

                Log.Logger.Information("==== Launched ====");
                Log.Logger.Information($"Version {VersionDetection.GetCurrentVersion()}");
            }
            catch (Exception ex)
            {
                // logging won't work but silently fails
                EventTracker.Error(ex, "Logging cannot be configured");

                // "no-op" logger
                Log.Logger = new LoggerConfiguration().CreateLogger();
            }
        }
Beispiel #2
0
        private void FixObjectTypes(object data, Type type, OpenTagCache srcInfo)
        {
            // The object type enum changed in 11.1.498295 because a new armor type was added at value 3.
            // These are a bunch of hacks to fix this in most cases.
            var oldObjectTypeField = type.GetField("ObjectTypeOld");
            var newObjectTypeField = type.GetField("ObjectTypeNew");

            if (oldObjectTypeField != null && newObjectTypeField != null)
            {
                if (VersionDetection.Compare(srcInfo.Version, EngineVersion.V11_1_498295_Live) < 0)
                {
                    var oldType = (ObjectTypeValueOld)oldObjectTypeField.GetValue(data);
                    newObjectTypeField.SetValue(data, ConvertObjectType(oldType));
                }
                else
                {
                    var newType = (ObjectTypeValueNew)newObjectTypeField.GetValue(data);
                    oldObjectTypeField.SetValue(data, ConvertObjectType(newType));
                }
            }
            var phantom = data as PhysicsModel.PhantomType;

            if (phantom != null)
            {
                // Remove the armor bit added at position 8 in flags
                phantom.Flags = (uint)((phantom.Flags & ~0x1FFE00) | ((phantom.Flags & 0x1FFE00) >> 1));
            }
            var chmt = data as ChocolateMountainNew;

            if (chmt != null && chmt.LightingVariables != null && chmt.LightingVariables.Count > 3)
            {
                chmt.LightingVariables.RemoveAt(3); // Remove armor data from chmt
            }
        }
 /// <summary>
 /// Creates a vertex stream for a given engine version.
 /// </summary>
 /// <param name="version">The engine version.</param>
 /// <param name="stream">The base stream.</param>
 /// <returns>The created vertex stream.</returns>
 public static IVertexStream Create(EngineVersion version, Stream stream)
 {
     if (VersionDetection.Compare(version, EngineVersion.V1_235640_cert_ms25) >= 0)
     {
         return(new V1_235640.VertexStream(stream));
     }
     return(new V1_106708.VertexStream(stream));
 }
Beispiel #4
0
        private static void ConfigureLogger()
        {
            var logsDirectory = FileUtils.GetLogFolder();

            Log.Logger = new LoggerConfiguration()
                         .MinimumLevel.ControlledBy(LogLevelSwitchService.LevelSwitch)
                         .WriteTo.File(Path.Combine(logsDirectory, "log-.txt"), retainedFileCountLimit: 28, rollingInterval: RollingInterval.Day)
                         .CreateLogger();

            Log.Logger.Information("==== Launched ====");
            Log.Logger.Information($"Version {VersionDetection.GetCurrentVersion()}");
        }
        private static TagStructureAttribute GetStructureAttribute(Type type, EngineVersion version)
        {
            // First match against any TagStructureAttributes that have version restrictions
            var attrib = type.GetCustomAttributes(typeof(TagStructureAttribute), false)
                         .Cast <TagStructureAttribute>()
                         .Where(a => a.MinVersion != EngineVersion.Unknown || a.MaxVersion != EngineVersion.Unknown)
                         .FirstOrDefault(a => VersionDetection.IsBetween(version, a.MinVersion, a.MaxVersion));

            // If nothing was found, find the first attribute without any version restrictions
            return(attrib ?? type.GetCustomAttributes(typeof(TagStructureAttribute), false)
                   .Cast <TagStructureAttribute>()
                   .FirstOrDefault(a => a.MinVersion == EngineVersion.Unknown && a.MaxVersion == EngineVersion.Unknown));
        }
Beispiel #6
0
        private void ConfigureLogger()
        {
            string logsDirectory = FileUtils.GetLogFolder();

            Log.Logger = new LoggerConfiguration()
                         .MinimumLevel.ControlledBy(LogLevelSwitchService.LevelSwitch)
                         .WriteTo.RollingFile(Path.Combine(logsDirectory, "log-{Date}.txt"), retainedFileCountLimit: 28)
#if DEBUG
                         .WriteTo.Console()
#endif
                         .CreateLogger();

            Log.Logger.Information("==== Launched ====");
            Log.Logger.Information($"Version {VersionDetection.GetCurrentVersion()}");
        }
Beispiel #7
0
 private void GetVersionData()
 {
     Task.Delay(2000).ContinueWith(_ =>
     {
         var latestVersion = VersionDetection.GetLatestReleaseVersion();
         if (latestVersion != null)
         {
             if (latestVersion != VersionDetection.GetCurrentVersion())
             {
                 // there is a new version....
                 IsNewVersionAvailable = true;
                 RaisePropertyChanged(nameof(IsNewVersionAvailable));
             }
         }
     });
 }
Beispiel #8
0
        private ResourceLocation FixResourceLocation(ResourceLocation location, EngineVersion srcVersion, EngineVersion destVersion)
        {
            if (VersionDetection.Compare(destVersion, EngineVersion.V1_235640_cert_ms25) >= 0)
            {
                return(location);
            }
            switch (location)
            {
            case ResourceLocation.RenderModels:
                return(ResourceLocation.Resources);

            case ResourceLocation.Lightmaps:
                return(ResourceLocation.Textures);
            }
            return(location);
        }
Beispiel #9
0
        private bool GetCurrentPropertyInfo()
        {
            // If the field has a TagFieldAttribute, use it, otherwise use the default
            Attribute = Field.GetCustomAttributes(typeof(TagFieldAttribute), false).FirstOrDefault() as TagFieldAttribute ?? DefaultFieldAttribute;
            if (Attribute.Offset >= Info.TotalSize)
            {
                throw new InvalidOperationException("Offset for property \"" + Field.Name + "\" is outside of its structure");
            }

            // Read version restrictions, if any
            var minVersionAttrib = Field.GetCustomAttributes(typeof(MinVersionAttribute), false).FirstOrDefault() as MinVersionAttribute;
            var maxVersionAttrib = Field.GetCustomAttributes(typeof(MaxVersionAttribute), false).FirstOrDefault() as MaxVersionAttribute;

            MinVersion = (minVersionAttrib != null) ? minVersionAttrib.Version : EngineVersion.Unknown;
            MaxVersion = (maxVersionAttrib != null) ? maxVersionAttrib.Version : EngineVersion.Unknown;
            return(VersionDetection.IsBetween(Info.Version, MinVersion, MaxVersion));
        }
Beispiel #10
0
    /// <summary>
    ///     Display the program startup banner
    /// </summary>
    /// <remarks>Generated from https://www.coolgenerator.com/ascii-text-generator  Font: Roman</remarks>
    public static void Show()
    {
        const string banner = @"
oooooooooo.               o8o  oooo        .o8  oooooooooo.                .
`888'   `Y8b              `""'  `888       ""888  `888'   `Y8b             .o8
 888     888 oooo  oooo  oooo   888   .oooo888   888     888  .ooooo.  .o888oo
 888oooo888' `888  `888  `888   888  d88' `888   888oooo888' d88' `88b   888
 888    `88b  888   888   888   888  888   888   888    `88b 888   888   888
 888    .88P  888   888   888   888  888   888   888    .88P 888   888   888 .
o888bood8P'   `V88V""V8P' o888o o888o `Y8bod88P"" o888bood8P'  `Y8bod8P'   ""888""


";

        Console.WriteLine(banner);

        string version = VersionDetection.ProgramVersion(typeof(StartupBanner));

        Console.WriteLine(value: $"Starting version {version}...");
    }
        public override bool Execute(List <string> args)
        {
            if (args.Count < 2)
            {
                return(false);
            }
            var outputPath = args[0];

            // Load each file and do version detection
            var infos = new List <OpenTagCache>();

            foreach (var path in args.Skip(1))
            {
                Console.WriteLine("Loading {0}...", path);

                // Load the cache file
                var info = new OpenTagCache {
                    CacheFile = new FileInfo(path)
                };
                using (var stream = info.OpenCacheRead())
                    info.Cache = new TagCache(stream);

                // Do version detection, and don't accept the closest version
                // because that might not work
                EngineVersion closestVersion;
                info.Version = VersionDetection.DetectVersion(info.Cache, out closestVersion);
                if (info.Version == EngineVersion.Unknown)
                {
                    Console.WriteLine("- Unrecognized version! Ignoring.");
                    continue;
                }
                info.Deserializer = new TagDeserializer(info.Version);
                infos.Add(info);
            }

            var result = new TagVersionMap();

            using (var baseStream = _info.OpenCacheRead())
            {
                // Get the scenario tags for this cache
                Console.WriteLine("Finding base scenario tags...");
                var baseScenarios = FindScenarios(_info, baseStream);
                var baseVersion   = _info.Version;
                var baseTagData   = new Dictionary <int, object>();
                foreach (var scenario in baseScenarios)
                {
                    baseTagData[scenario.Tag.Index] = scenario.Data;
                }

                // Now compare with each of the other caches
                foreach (var info in infos)
                {
                    using (var stream = info.OpenCacheRead())
                    {
                        Console.WriteLine("Finding scenario tags in {0}...", info.CacheFile.FullName);

                        // Get the scenario tags and connect them to the base tags
                        var scenarios     = FindScenarios(info, stream);
                        var tagsToCompare = new Queue <QueuedTag>();
                        for (var i = 0; i < scenarios.Count; i++)
                        {
                            tagsToCompare.Enqueue(scenarios[i]);
                            if (i < baseScenarios.Count)
                            {
                                result.Add(baseVersion, baseScenarios[i].Tag.Index, info.Version, scenarios[i].Tag.Index);
                            }
                        }

                        // Process each tag in the queue, enqueuing all of its dependencies as well
                        while (tagsToCompare.Count > 0)
                        {
                            // Get the tag and its data
                            var tag = tagsToCompare.Dequeue();
                            TagPrinter.PrintTagShort(tag.Tag);
                            var data = tag.Data;
                            if (data == null)
                            {
                                // No data yet - deserialize it
                                var context = new TagSerializationContext(stream, info.Cache, info.StringIds, tag.Tag);
                                var type    = TagStructureTypes.FindByGroupTag(tag.Tag.Group.Tag);
                                data = info.Deserializer.Deserialize(context, type);
                            }

                            // Now get the data for the base tag
                            var baseTag = result.Translate(info.Version, tag.Tag.Index, baseVersion);
                            if (baseTag == -1 || _info.Cache.Tags[baseTag].Group.Tag != tag.Tag.Group.Tag)
                            {
                                continue;
                            }
                            object baseData;
                            if (!baseTagData.TryGetValue(baseTag, out baseData))
                            {
                                // No data yet - deserialize it
                                var context = new TagSerializationContext(baseStream, _info.Cache, _info.StringIds, _info.Cache.Tags[baseTag]);
                                var type    = TagStructureTypes.FindByGroupTag(tag.Tag.Group.Tag);
                                baseData             = _info.Deserializer.Deserialize(context, type);
                                baseTagData[baseTag] = baseData;
                            }

                            // Compare the two blocks
                            CompareBlocks(baseData, baseVersion, data, info.Version, result, tagsToCompare);
                        }
                    }
                }
            }

            // Write out the CSV
            Console.WriteLine("Writing results...");
            using (var writer = new StreamWriter(File.Open(outputPath, FileMode.Create, FileAccess.Write)))
                result.WriteCsv(writer);

            Console.WriteLine("Done!");
            return(true);
        }
        private static void CompareBlocks(object leftData, EngineVersion leftVersion, object rightData, EngineVersion rightVersion, TagVersionMap result, Queue <QueuedTag> tagQueue)
        {
            if (leftData == null || rightData == null)
            {
                return;
            }
            var type = leftData.GetType();

            if (type == typeof(TagInstance))
            {
                // If the objects are tags, then we've found a match
                var leftTag  = (TagInstance)leftData;
                var rightTag = (TagInstance)rightData;
                if (leftTag.Group.Tag != rightTag.Group.Tag)
                {
                    return;
                }
                if (leftTag.IsInGroup("rmt2") || leftTag.IsInGroup("rmdf") || leftTag.IsInGroup("vtsh") || leftTag.IsInGroup("pixl") || leftTag.IsInGroup("rm  ") || leftTag.IsInGroup("bitm"))
                {
                    return;
                }
                var translated = result.Translate(leftVersion, leftTag.Index, rightVersion);
                if (translated >= 0)
                {
                    return;
                }
                result.Add(leftVersion, leftTag.Index, rightVersion, rightTag.Index);
                tagQueue.Enqueue(new QueuedTag {
                    Tag = rightTag
                });
            }
            else if (type.IsArray)
            {
                if (type.GetElementType().IsPrimitive)
                {
                    return;
                }

                // If the objects are arrays, then loop through each element
                var leftArray  = (Array)leftData;
                var rightArray = (Array)rightData;
                if (leftArray.Length != rightArray.Length)
                {
                    return; // If the sizes are different, we probably can't compare them
                }
                for (var i = 0; i < leftArray.Length; i++)
                {
                    CompareBlocks(leftArray.GetValue(i), leftVersion, rightArray.GetValue(i), rightVersion, result, tagQueue);
                }
            }
            else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List <>))
            {
                if (type.GenericTypeArguments[0].IsPrimitive)
                {
                    return;
                }

                // If the objects are lists, then loop through each element
                var countProperty = type.GetProperty("Count");
                var leftCount     = (int)countProperty.GetValue(leftData);
                var rightCount    = (int)countProperty.GetValue(rightData);
                if (leftCount != rightCount)
                {
                    return; // If the sizes are different, we probably can't compare them
                }
                var getItem = type.GetMethod("get_Item");
                for (var i = 0; i < leftCount; i++)
                {
                    var leftItem  = getItem.Invoke(leftData, new object[] { i });
                    var rightItem = getItem.Invoke(rightData, new object[] { i });
                    CompareBlocks(leftItem, leftVersion, rightItem, rightVersion, result, tagQueue);
                }
            }
            else if (type.GetCustomAttributes(typeof(TagStructureAttribute), false).Length > 0)
            {
                // The objects are structures
                var left  = new TagFieldEnumerator(new TagStructureInfo(leftData.GetType(), leftVersion));
                var right = new TagFieldEnumerator(new TagStructureInfo(rightData.GetType(), rightVersion));
                while (left.Next() && right.Next())
                {
                    // Keep going on the left until the field is on the right
                    while (!VersionDetection.IsBetween(rightVersion, left.MinVersion, left.MaxVersion))
                    {
                        if (!left.Next())
                        {
                            return;
                        }
                    }

                    // Keep going on the right until the field is on the left
                    while (!VersionDetection.IsBetween(leftVersion, right.MinVersion, right.MaxVersion))
                    {
                        if (!right.Next())
                        {
                            return;
                        }
                    }
                    if (left.Field.MetadataToken != right.Field.MetadataToken)
                    {
                        throw new InvalidOperationException("WTF, left and right fields don't match!");
                    }

                    // Process the fields
                    var leftFieldData  = left.Field.GetValue(leftData);
                    var rightFieldData = right.Field.GetValue(rightData);
                    CompareBlocks(leftFieldData, leftVersion, rightFieldData, rightVersion, result, tagQueue);
                }
            }
        }
Beispiel #13
0
        public override bool Execute(List <string> args)
        {
            if (args.Count != 4)
            {
                return(false);
            }
            var srcTag = ArgumentParser.ParseTagIndex(_info.Cache, args[0]);

            if (srcTag == null)
            {
                return(false);
            }
            var csvPath    = args[1];
            var csvOutPath = args[2];
            var targetDir  = args[3];

            // Load the CSV
            Console.WriteLine("Reading {0}...", csvPath);
            TagVersionMap tagMap;

            using (var reader = new StreamReader(File.OpenRead(csvPath)))
                tagMap = TagVersionMap.ParseCsv(reader);

            // Load destination files
            Console.WriteLine("Loading the target tags.dat...");
            var destCachePath = Path.Combine(targetDir, "tags.dat");
            var destInfo      = new OpenTagCache {
                CacheFile = new FileInfo(destCachePath)
            };

            using (var stream = destInfo.OpenCacheRead())
                destInfo.Cache = new TagCache(stream);

            // Do version detection
            EngineVersion guessedVersion;

            destInfo.Version = VersionDetection.DetectVersion(destInfo.Cache, out guessedVersion);
            if (destInfo.Version == EngineVersion.Unknown)
            {
                Console.WriteLine("Unrecognized target version!");
                return(true);
            }
            Console.WriteLine("- Detected version {0}", VersionDetection.GetVersionString(destInfo.Version));

            if (_info.Version != EngineVersion.V11_1_498295_Live && destInfo.Version != EngineVersion.V1_106708_cert_ms23)
            {
                Console.Error.WriteLine("Conversion is only supported from 11.1.498295 Live to 1.106708 cert_ms23.");
                return(true);
            }

            // Set up version-specific objects
            destInfo.Serializer   = new TagSerializer(destInfo.Version);
            destInfo.Deserializer = new TagDeserializer(destInfo.Version);
            StringIdResolverBase resolver;

            if (VersionDetection.Compare(destInfo.Version, EngineVersion.V11_1_498295_Live) >= 0)
            {
                resolver = new V11_1_498295.StringIdResolver();
            }
            else
            {
                resolver = new V1_106708.StringIdResolver();
            }

            // Load stringIDs
            Console.WriteLine("Loading the target string_ids.dat...");
            var destStringIdsPath = Path.Combine(targetDir, "string_ids.dat");

            destInfo.StringIdsFile = new FileInfo(destStringIdsPath);
            using (var stream = destInfo.StringIdsFile.OpenRead())
                destInfo.StringIds = new StringIdCache(stream, resolver);

            // Load resources for the target build
            Console.WriteLine("Loading target resources...");
            var destResources = new ResourceDataManager();

            destResources.LoadCachesFromDirectory(destInfo.CacheFile.DirectoryName);

            // Load resources for our build
            Console.WriteLine("Loading source resources...");
            var srcResources = new ResourceDataManager();

            srcResources.LoadCachesFromDirectory(_info.CacheFile.DirectoryName);

            Console.WriteLine();
            Console.WriteLine("CONVERTING FROM VERSION {0} TO {1}", VersionDetection.GetVersionString(_info.Version), VersionDetection.GetVersionString(destInfo.Version));
            Console.WriteLine();

            TagInstance resultTag;

            using (Stream srcStream = _info.OpenCacheRead(), destStream = destInfo.OpenCacheReadWrite())
                resultTag = ConvertTag(srcTag, _info, srcStream, srcResources, destInfo, destStream, destResources, tagMap);

            Console.WriteLine();
            Console.WriteLine("Repairing decal systems...");
            FixDecalSystems(destInfo, resultTag.Index);

            Console.WriteLine();
            Console.WriteLine("Saving stringIDs...");
            using (var stream = destInfo.StringIdsFile.Open(FileMode.Open, FileAccess.ReadWrite))
                destInfo.StringIds.Save(stream);

            Console.WriteLine("Writing {0}...", csvOutPath);
            using (var stream = new StreamWriter(File.Open(csvOutPath, FileMode.Create, FileAccess.ReadWrite)))
                tagMap.WriteCsv(stream);

            // Uncomment this to add the new tag as a dependency to cfgt to make testing easier

            /*using (var stream = destInfo.OpenCacheReadWrite())
             * {
             *  destInfo.Cache.Tags[0].Dependencies.Add(resultTag.Index);
             *  destInfo.Cache.UpdateTag(stream, destInfo.Cache.Tags[0]);
             * }*/

            Console.WriteLine();
            Console.WriteLine("All done! The converted tag is:");
            TagPrinter.PrintTagShort(resultTag);
            return(true);
        }
Beispiel #14
0
        private GeometryReference ConvertGeometry(GeometryReference geometry, OpenTagCache srcInfo, ResourceDataManager srcResources, OpenTagCache destInfo, ResourceDataManager destResources)
        {
            if (geometry == null || geometry.Resource == null || geometry.Resource.Index < 0)
            {
                return(geometry);
            }

            // The format changed starting with version 1.235640, so if both versions are on the same side then they can be converted normally
            var srcCompare  = VersionDetection.Compare(srcInfo.Version, EngineVersion.V1_235640_cert_ms25);
            var destCompare = VersionDetection.Compare(destInfo.Version, EngineVersion.V1_235640_cert_ms25);

            if ((srcCompare < 0 && destCompare < 0) || (srcCompare >= 0 && destCompare >= 0))
            {
                geometry.Resource = ConvertResource(geometry.Resource, srcInfo, srcResources, destInfo, destResources);
                return(geometry);
            }

            Console.WriteLine("- Rebuilding geometry resource {0} in {1}...", geometry.Resource.Index, geometry.Resource.GetLocation());
            using (MemoryStream inStream = new MemoryStream(), outStream = new MemoryStream())
            {
                // First extract the model data
                srcResources.Extract(geometry.Resource, inStream);

                // Now open source and destination vertex streams
                inStream.Position = 0;
                var inVertexStream  = VertexStreamFactory.Create(srcInfo.Version, inStream);
                var outVertexStream = VertexStreamFactory.Create(destInfo.Version, outStream);

                // Deserialize the definition data
                var resourceContext = new ResourceSerializationContext(geometry.Resource);
                var definition      = srcInfo.Deserializer.Deserialize <RenderGeometryResourceDefinition>(resourceContext);

                // Convert each vertex buffer
                foreach (var buffer in definition.VertexBuffers)
                {
                    ConvertVertexBuffer(buffer.Definition, inStream, inVertexStream, outStream, outVertexStream);
                }

                // Copy each index buffer over
                foreach (var buffer in definition.IndexBuffers)
                {
                    if (buffer.Definition.Data.Size == 0)
                    {
                        continue;
                    }
                    inStream.Position = buffer.Definition.Data.Address.Offset;
                    buffer.Definition.Data.Address = new ResourceAddress(ResourceAddressType.Resource, (int)outStream.Position);
                    var bufferData = new byte[buffer.Definition.Data.Size];
                    inStream.Read(bufferData, 0, bufferData.Length);
                    outStream.Write(bufferData, 0, bufferData.Length);
                    StreamUtil.Align(outStream, 4);
                }

                // Update the definition data
                destInfo.Serializer.Serialize(resourceContext, definition);

                // Now inject the new resource data
                var newLocation = FixResourceLocation(geometry.Resource.GetLocation(), srcInfo.Version, destInfo.Version);
                outStream.Position = 0;
                destResources.Add(geometry.Resource, newLocation, outStream);
            }
            return(geometry);
        }