Esempio n. 1
0
        public static void Export(MetaMap map, TextWriter writer, bool unreachableIsSolid = true)
        {
            string DetermineCharacter(int x, int y) =>
            map[x, y] switch
            {
                TileType.Empty => " ",
                TileType.Wall => "█",
                TileType.Door => "□",
                TileType.PushWall => "□",
                TileType.Unreachable => unreachableIsSolid ? "█" : " ",
                _ => "!"
            };

            for (int y = 0; y < map.Height; y++)
            {
                for (int x = 0; x < map.Width; x++)
                {
                    writer.Write(DetermineCharacter(x, y));
                }
                if (y < map.Height - 1)
                {
                    writer.WriteLine();
                }
            }

            writer.Flush();
        }
    }
Esempio n. 2
0
        private void EstimateMapSize(MetaMap map, uint mapAddress, MemoryMap memMap, int entryCount)
        {
            bool alreadyVisited = map.HasSizeEstimates;

            int newSize = memMap.EstimateBlockSize(mapAddress);

            map.EstimateSize(newSize / entryCount);
            map.Truncate(newSize);

            if (alreadyVisited)
            {
                return;
            }

            foreach (MetaValueGuess guess in map.Guesses)
            {
                if (guess.Type != MetaValueType.Reflexive)
                {
                    continue;
                }

                MetaMap subMap = map.GetSubMap(guess.Offset);
                if (subMap != null)
                {
                    EstimateMapSize(subMap, guess.Pointer, memMap, (int)guess.Data1);
                }
            }
        }
Esempio n. 3
0
        private void WritePlugin(MetaMap map, int size, IPluginVisitor writer)
        {
            for (int offset = 0; offset < size; offset += 4)
            {
                MetaValueGuess guess = map.GetGuess(offset);
                if (guess != null)
                {
                    switch (guess.Type)
                    {
                    case MetaValueType.DataReference:
                        if (offset <= size - 0x14)
                        {
                            writer.VisitDataReference("Unknown", (uint)offset, "bytes", false, 4, 0);
                            offset += 0x10;
                            continue;
                        }
                        break;

                    case MetaValueType.TagReference:
                        if (offset <= size - 0x10)
                        {
                            writer.VisitTagReference("Unknown", (uint)offset, false, true, true, 0);
                            offset += 0xC;
                            continue;
                        }
                        break;

                    case MetaValueType.Reflexive:
                        if (offset <= size - 0xC)
                        {
                            MetaMap subMap = map.GetSubMap(offset);
                            if (subMap != null)
                            {
                                int subMapSize = subMap.GetBestSizeEstimate();
                                writer.EnterReflexive("Unknown", (uint)offset, false, (uint)subMapSize, 4, 0);
                                WritePlugin(subMap, subMapSize, writer);
                                writer.LeaveReflexive();
                                offset += 0x8;
                                continue;
                            }
                        }
                        break;
                    }
                }

                // Just write an unknown value depending upon how much space we have left
                if (offset <= size - 4)
                {
                    writer.VisitUndefined("Unknown", (uint)offset, false, 0);
                }
                else if (offset <= size - 2)
                {
                    writer.VisitInt16("Unknown", (uint)offset, false, 0);
                }
                else
                {
                    writer.VisitInt8("Unknown", (uint)offset, false, 0);
                }
            }
        }
        public static void Export(MetaMap map, MapPalette palette, string outputFilePath, int scale = 1)
        {
            using var image = new FastImage(map.Width, map.Height, scale);
            for (var tileY = 0; tileY < map.Height; tileY++)
            {
                for (var tileX = 0; tileX < map.Width; tileX++)
                {
                    var tileColor = palette.PickColor(map[tileX, tileY]);
                    image.SetPixel(tileX, tileY, tileColor);
                }
            }

            image.Save(outputFilePath);
        }
Esempio n. 5
0
        private static void RunOptionsAndReturnExitCode(Options opts)
        {
            var map = MetaMap.Load(opts.InputMapPath);

            var imageName = opts.ImageName;

            if (!string.IsNullOrEmpty(imageName))
            {
                if (!imageName.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase))
                {
                    imageName += ".png";
                }
            }
            else
            {
                imageName = Path.GetFileNameWithoutExtension(opts.InputMapPath) + ".png";
            }
Esempio n. 6
0
        private static void ConvertMetaMapsToImages(IEnumerable <string> inputFiles, string outputPath)
        {
            var allFiles = inputFiles.ToArray();

            if (Directory.Exists(outputPath))
            {
                Directory.Delete(outputPath, recursive: true);
            }
            Directory.CreateDirectory(outputPath);

            using var progress = new ProgressBar(allFiles.Length, "Converting images...");
            Parallel.ForEach(allFiles, mapPath =>
            {
                var imagePath = Path.Combine(outputPath, Path.GetFileNameWithoutExtension(mapPath) + ".png");
                var metaMap   = MetaMap.Load(mapPath);

                MetaMapImageExporter.Export(metaMap, MapPalette.Full, imagePath, scale: 4);
                progress.Tick();
            });
        }
Esempio n. 7
0
        private void GenerateSubMaps(Queue <MetaMap> maps, MetaAnalyzer analyzer, IReader reader, ICacheFile cacheFile)
        {
            var generatedMaps = new Dictionary <uint, MetaMap>();

            while (maps.Count > 0)
            {
                MetaMap map = maps.Dequeue();
                foreach (MetaValueGuess guess in map.Guesses.Where(guess => guess.Type == MetaValueType.Reflexive))
                {
                    MetaMap subMap;
                    if (!generatedMaps.TryGetValue(guess.Pointer, out subMap))
                    {
                        subMap = new MetaMap();
                        reader.SeekTo(cacheFile.MetaArea.PointerToOffset(guess.Pointer));
                        analyzer.AnalyzeArea(reader, guess.Pointer, subMap);
                        maps.Enqueue(subMap);
                        generatedMaps[guess.Pointer] = subMap;
                    }
                    map.AssociateSubMap(guess.Offset, subMap);
                }
            }
        }
Esempio n. 8
0
        public void ShouldRoundTripMetaMap()
        {
            var numTypes = Enum.GetValues(typeof(TileType)).Length;

            var m = new MetaMap(4, 5);

            for (int y = 0; y < m.Height; y++)
            {
                for (int x = 0; x < m.Width; x++)
                {
                    m[x, y] = (TileType)((y * m.Width + x) % numTypes);
                }
            }

            var tempPath = Path.GetTempFileName();

            try
            {
                m.Save(tempPath);
                var roundTripped = MetaMap.Load(tempPath);

                roundTripped.Width.Should().Be(m.Width);
                roundTripped.Height.Should().Be(m.Height);
                for (int y = 0; y < m.Height; y++)
                {
                    for (int x = 0; x < m.Width; x++)
                    {
                        roundTripped[x, y].Should().Be(m[x, y], $"should have matched at ({x},{y})");
                    }
                }
            }
            finally
            {
                if (File.Exists(tempPath))
                {
                    File.Delete(tempPath);
                }
            }
        }
Esempio n. 9
0
        private void FoldSubMaps(MetaMap map)
        {
            foreach (MetaValueGuess guess in map.Guesses)
            {
                if (guess.Type != MetaValueType.Reflexive)
                {
                    continue;
                }

                MetaMap subMap = map.GetSubMap(guess.Offset);
                if (subMap == null)
                {
                    continue;
                }

                //var entryCount = (int)guess.Data1;
                int firstBlockSize = subMap.GetBestSizeEstimate();
                //if (firstBlockSize > 0 && !subMap.IsFolded(firstBlockSize))
                //{
                subMap.Fold(firstBlockSize);
                FoldSubMaps(subMap);
                //}
            }
        }
Esempio n. 10
0
        private void worker_DoWork(object sender, DoWorkEventArgs e, IList <MapEntry> generatorMaps, string outputPath,
                                   BackgroundWorker worker)
        {
            var      globalMaps     = new Dictionary <string, MetaMap>();
            DateTime startTime      = DateTime.Now;
            string   gameIdentifier = "";

            worker.ReportProgress(0);

            for (int i = 0; i < generatorMaps.Count; i++)
            {
                var tagMaps = new Dictionary <ITag, MetaMap>();

                IReader reader;
                KeyValuePair <ICacheFile, EngineDescription> cacheData = LoadMap(generatorMaps[i].LocalMapPath, out reader);
                ICacheFile cacheFile = cacheData.Key;
                var        analyzer  = new MetaAnalyzer(cacheFile);
                if (gameIdentifier == "")
                {
                    gameIdentifier = cacheData.Value.Settings.GetSetting <string>("shortName");
                }

                var mapsToProcess = new Queue <MetaMap>();
                foreach (ITag tag in cacheFile.Tags)
                {
                    if (tag.MetaLocation == null)
                    {
                        continue;
                    }

                    var map = new MetaMap();
                    tagMaps[tag] = map;
                    mapsToProcess.Enqueue(map);

                    reader.SeekTo(tag.MetaLocation.AsOffset());
                    analyzer.AnalyzeArea(reader, tag.MetaLocation.AsPointer(), map);
                }
                GenerateSubMaps(mapsToProcess, analyzer, reader, cacheFile);

                var classMaps = new Dictionary <string, MetaMap>();
                foreach (ITag tag in cacheFile.Tags)
                {
                    if (tag.MetaLocation == null)
                    {
                        continue;
                    }

                    MetaMap map = tagMaps[tag];
                    EstimateMapSize(map, tag.MetaLocation.AsPointer(), analyzer.GeneratedMemoryMap, 1);

                    string  magicStr = CharConstant.ToString(tag.Class.Magic);
                    MetaMap oldClassMap;
                    if (classMaps.TryGetValue(magicStr, out oldClassMap))
                    {
                        oldClassMap.MergeWith(map);
                    }
                    else
                    {
                        classMaps[magicStr] = map;
                    }
                }

                foreach (var map in classMaps)
                {
                    MetaMap globalMap;
                    if (globalMaps.TryGetValue(map.Key, out globalMap))
                    {
                        globalMap.MergeWith(map.Value);
                    }
                    else
                    {
                        globalMaps[map.Key] = map.Value;
                    }
                }

                reader.Close();

                worker.ReportProgress(100 * (i + 1) / (generatorMaps.Count));
            }

            string badChars = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());

            foreach (var map in globalMaps)
            {
                string filename = badChars.Aggregate(map.Key, (current, badChar) => current.Replace(badChar, '_'));
                filename += ".xml";
                string path = Path.Combine(outputPath, filename);

                var settings = new XmlWriterSettings
                {
                    Indent      = true,
                    IndentChars = "\t"
                };
                using (XmlWriter writer = XmlWriter.Create(path, settings))
                {
                    var pluginWriter = new AssemblyPluginWriter(writer, gameIdentifier);

                    int size = map.Value.GetBestSizeEstimate();
                    FoldSubMaps(map.Value);

                    pluginWriter.EnterPlugin(size);

                    pluginWriter.EnterRevisions();
                    pluginWriter.VisitRevision(new PluginRevision("Assembly", 1, "Generated plugin from scratch."));
                    pluginWriter.LeaveRevisions();

                    WritePlugin(map.Value, size, pluginWriter);
                    pluginWriter.LeavePlugin();
                }
            }

            DateTime endTime = DateTime.Now;

            e.Result = endTime.Subtract(startTime);
        }
Esempio n. 11
0
 public static void Export(MetaMap map, string outputFilePath, bool unreachableIsSolid = true)
 {
     using var fs = File.CreateText(outputFilePath);
     Export(map, fs, unreachableIsSolid);
 }