private void MenuItemFileOpen_Click(object sender, EventArgs e) { OpenFileDialog open = new OpenFileDialog(); open.Title = "Open File"; open.Filter = "Map File (*.map)|*.map|Level file (*.lvl)|*.lvl"; if (!String.IsNullOrEmpty(mainController.CurrentWorkingDirectory)) { open.InitialDirectory = mainController.CurrentWorkingDirectory; } if (open.ShowDialog() == DialogResult.OK) { if (open.InitialDirectory != mainController.CurrentWorkingDirectory) { mainController.CurrentWorkingDirectory = Directory.GetCurrentDirectory(); } var level = new LevelFile(); Stream input; if ((input = open.OpenFile()) != null) { level.Deserialize(input); FileName = open.SafeFileName; input.Close(); //Strip duplicated blobs for (int i = 0; i < level.Floors.Count; i++) { var floor = level.Floors[i]; if (floor.FileName != null && floor.FileName.EndsWith(".lvb.blo") == true) { floor.FileName = null; level.Floors[i] = floor; } } for (int i = 0; i < level.Objects.Count; i++) { var obj = level.Objects[i]; if (obj.FileName != null && obj.FileName.EndsWith(".lvb.blo") == true) { obj.FileName = null; level.Objects[i] = obj; } } } mainController.LoadLevel(level); } open.Dispose(); }
private void openToolStripMenuItem_Click(object sender, EventArgs e) { var dialog = new OpenFileDialog(); dialog.Filter = "Infantry Online Level File (*.lvl)|*.lvl"; if (dialog.ShowDialog() == DialogResult.OK) { var file = new LevelFile(); var fileName = dialog.SafeFileName; var filePath = dialog.FileName; var stream = dialog.OpenFile(); file.Deserialize(stream); // Initialize the tiles and objects. // Most tiles will only have a handful of atlas lookups, so rather than going through the whole thing, // use a dictionary and make quick work of it. Dictionary <string, Tuple <int, int> > atlasLookup = new Dictionary <string, Tuple <int, int> >(); for (int i = 0; i < file.Width; i++) { for (int j = 0; j < file.Height; j++) { // TODO: Deal with this. Why are some maps so bloody large? if (i >= 2048 || j >= 2048) { continue; } // Map across the floor array and into the atlas, because we don't care where the data really comes from. var tile = file.Tiles[j * file.Width + i]; var blobName = file.Floors[tile.TerrainLookup].FileName.ToLower().Trim(); var cfsName = file.Floors[tile.TerrainLookup].Id.ToLower().Trim(); if (blobName == null) { // Dealing with a shady file. Deal with this later. throw new NotImplementedException("Deal with this later."); } var dictKey = $"{blobName}#{cfsName}"; var atlasIndex = -1; var atlasEntryIndex = -1; if (!atlasLookup.ContainsKey(dictKey)) { foreach (var atlas in Renderer.FloorAtlasses) { var foundCfs = atlas.Entries.FirstOrDefault(entry => entry.CfsBitmap.BloFilename == blobName && entry.CfsBitmap.CfsFilename == cfsName); if (foundCfs != null) { atlasIndex = Renderer.FloorAtlasses.IndexOf(atlas); atlasEntryIndex = atlas.Entries.IndexOf(foundCfs); break; } } atlasLookup[dictKey] = new Tuple <int, int>(atlasIndex, atlasEntryIndex); } else { atlasIndex = atlasLookup[dictKey].Item1; atlasEntryIndex = atlasLookup[dictKey].Item2; } if (atlasIndex == -1 || atlasEntryIndex == -1) { throw new NotImplementedException("Atlas entry not found!"); } Renderer.FloorRenderer.UpdateTileAtGlobalCoordinate(i, j, atlasIndex, atlasEntryIndex); } } // TODO: Code below works,but get the tiles to render first. //foreach(var entity in file.Entities) //{ // // Map across the Objects array and into the atlas, because we don't care where the data really comes from. // var obj = file.Objects[entity.ObjectId]; // var blobName = obj.FileName.ToLower().Trim(); // var cfsName = obj.Id.ToLower().Trim(); // if (blobName == null) // { // // Dealing with a shady file. Deal with this later. // throw new NotImplementedException("Deal with this later."); // } // CfsBitmap cfs = null; // foreach (var atlas in Renderer.ObjectAtlasses) // { // var foundCfs = atlas.Entries // .FirstOrDefault(entry => entry.CfsBitmap.BloFilename == blobName // && entry.CfsBitmap.CfsFilename == cfsName // && entry.CfsBitmap.FrameIndex == entity.FrameIndex); // if (foundCfs != null) // { // cfs = foundCfs.CfsBitmap; // break; // } // } // if (cfs == null) // { // throw new NotImplementedException("What do we do here?"); // } //} } }
public static void Main(string[] args) { bool showHelp = false; bool resourceMapping = true; bool generateBlobs = false; bool stripDumbBlobs = false; var options = new OptionSet() { { "no-resource-mapping", "don't do resource mapping for older level files", v => resourceMapping = v == null }, { "g|generate-blobs", "generate blobs for older level files when resource mapping fails", v => generateBlobs = v != null }, { "s|strip-lvb-blob-references", "strip references to .lvb.blo blob files", v => stripDumbBlobs = v != null }, { "h|help", "show this message and exit", v => showHelp = v != null }, }; List <string> extras; try { extras = options.Parse(args); } catch (OptionException e) { Console.Write("{0}: ", GetExecutableName()); Console.WriteLine(e.Message); Console.WriteLine("Try `{0} --help' for more information.", GetExecutableName()); return; } if (extras.Count < 1 || extras.Count > 2 || showHelp == true) { Console.WriteLine("Usage: {0} [OPTIONS]+ input_lvl [output_map]", GetExecutableName()); Console.WriteLine(); Console.WriteLine("Options:"); options.WriteOptionDescriptions(Console.Out); return; } string inputPath = extras[0]; string outputPath = extras.Count > 1 ? extras[1] : Path.ChangeExtension(inputPath, ".map"); string lvbPath = Path.ChangeExtension(inputPath, ".lvb"); string lvbName = Path.GetFileName(lvbPath); var level = new LevelFile(); using (var input = File.OpenRead(inputPath)) { level.Deserialize(input); } if (stripDumbBlobs == true) { for (int i = 0; i < level.Floors.Count; i++) { var floor = level.Floors[i]; if (floor.FileName != null && floor.FileName.EndsWith(".lvb.blo") == true) { floor.FileName = null; level.Floors[i] = floor; } } for (int i = 0; i < level.Objects.Count; i++) { var obj = level.Objects[i]; if (obj.FileName != null && obj.FileName.EndsWith(".lvb.blo") == true) { obj.FileName = null; level.Objects[i] = obj; } } } var hasLevelBlob = level.Floors.Any(f => f.FileName == null) == true || level.Objects.Any(o => o.FileName == null) == true; var remap = new Dictionary <string, string>(); if (hasLevelBlob == true) { // TODO: decrap this block of code var resources = resourceMapping == true ? LoadBloTable() : new SortedDictionary <string, string>(); if (File.Exists(lvbPath) == false) { Console.WriteLine("Could not open '{0}'!", lvbPath); Console.WriteLine(); Console.WriteLine("Mapping of LVB resources to real locations isn't going to happen."); } else { using (var lvb = File.OpenRead(lvbPath)) { var levelBlob = new BlobFile(); levelBlob.Deserialize(lvb); var md5 = MD5.Create(); var unknownEntries = new List <BlobFile.Entry>(); foreach (var entry in levelBlob.Entries) { lvb.Seek(entry.Offset, SeekOrigin.Begin); var data = new byte[entry.Size]; if (lvb.Read(data, 0, data.Length) != data.Length) { throw new FormatException(); } var hash = md5.ComputeHash(data); var friendlyHash = BitConverter .ToString(hash) .Replace("-", "") .ToLowerInvariant(); if (resources.ContainsKey(friendlyHash) == true) { remap[entry.Name] = resources[friendlyHash]; } else { Console.WriteLine("Could not find real location for '{0},{1}'.", lvbName, entry.Name); unknownEntries.Add(entry); } } if (unknownEntries.Count > 0) { Console.WriteLine("Could not find all of the level blob resources."); if (generateBlobs == true) { // ReSharper disable JoinDeclarationAndInitializer string floorBlobName; // ReSharper restore JoinDeclarationAndInitializer floorBlobName = "f_!"; floorBlobName += Path.GetFileNameWithoutExtension(inputPath); floorBlobName = Path.ChangeExtension(floorBlobName, ".blo"); // ReSharper disable JoinDeclarationAndInitializer string floorBlobPath; // ReSharper restore JoinDeclarationAndInitializer floorBlobPath = Path.GetDirectoryName(inputPath); if (floorBlobPath == null) { throw new InvalidOperationException(); } floorBlobPath = Path.Combine(floorBlobPath, floorBlobName); Console.WriteLine("Creating '{0}'...", floorBlobPath); using (var output = File.Create(floorBlobPath)) { var floorBlob = new BlobFile { Version = 2, }; // generate fake entries var floors = unknownEntries .Where(f => f.Name.StartsWith("f")) .ToArray(); foreach (var floor in floors) { floorBlob.Entries.Add(new BlobFile.Entry() { Name = floor.Name, }); } floorBlob.Serialize(output); // generate real entries floorBlob.Entries.Clear(); foreach (var floor in floors) { Console.WriteLine(" adding '{0}'", floor.Name); lvb.Seek(floor.Offset, SeekOrigin.Begin); floorBlob.Entries.Add(new BlobFile.Entry() { Name = floor.Name, Offset = output.Position, Size = floor.Size, }); output.WriteFromStream(lvb, floor.Size); remap[floor.Name] = string.Format("{0},{1}", floorBlobName, floor.Name); } output.Seek(0, SeekOrigin.Begin); floorBlob.Serialize(output); } // ReSharper disable JoinDeclarationAndInitializer string objectBlobName; // ReSharper restore JoinDeclarationAndInitializer objectBlobName = "o_!"; objectBlobName += Path.GetFileNameWithoutExtension(inputPath); objectBlobName = Path.ChangeExtension(objectBlobName, ".blo"); // ReSharper disable JoinDeclarationAndInitializer string objectBlobPath; // ReSharper restore JoinDeclarationAndInitializer objectBlobPath = Path.GetDirectoryName(inputPath); if (objectBlobPath == null) { throw new InvalidOperationException(); } objectBlobPath = Path.Combine(objectBlobPath, objectBlobName); Console.WriteLine("Creating '{0}'...", objectBlobPath); using (var output = File.Create(objectBlobPath)) { var objectBlob = new BlobFile { Version = 2, }; // generate fake entries var objects = unknownEntries .Where(o => o.Name.StartsWith("o")) .ToArray(); foreach (var obj in objects) { objectBlob.Entries.Add(new BlobFile.Entry() { Name = obj.Name, }); } objectBlob.Serialize(output); // generate real entries objectBlob.Entries.Clear(); foreach (var obj in objects) { Console.WriteLine(" adding '{0}'", obj.Name); lvb.Seek(obj.Offset, SeekOrigin.Begin); objectBlob.Entries.Add(new BlobFile.Entry() { Name = obj.Name, Offset = output.Position, Size = obj.Size, }); output.WriteFromStream(lvb, obj.Size); remap[obj.Name] = string.Format("{0},{1}", objectBlobName, obj.Name); } output.Seek(0, SeekOrigin.Begin); objectBlob.Serialize(output); } } } } } } using (var output = File.Create(outputPath)) { var header = new Map.Header { Version = 9, Width = level.Width, Height = level.Height, EntityCount = level.Entities.Count, PhysicsLow = new short[32], }; // not right? DERP //header.OffsetX = level.OffsetX; //header.OffsetY = level.OffsetY; Array.Copy(level.PhysicsLow, header.PhysicsLow, level.PhysicsLow.Length); header.PhysicsHigh = new short[32]; Array.Copy(level.PhysicsHigh, header.PhysicsHigh, level.PhysicsHigh.Length); header.LightColorWhite = level.LightColorWhite; header.LightColorRed = level.LightColorRed; header.LightColorGreen = level.LightColorGreen; header.LightColorBlue = level.LightColorBlue; output.WriteStructure(header); for (int i = 0; i < 8192; i++) { if (i < level.TerrainIds.Length) { output.WriteValueU8((byte)level.TerrainIds[i]); } else { output.WriteValueU8(0); } } for (int i = 0; i < 2048; i++) { var reference = new Map.BlobReference(); if (i < level.Floors.Count) { var floor = level.Floors[i]; if (floor.FileName == null) { if (remap.ContainsKey(floor.Id) == true) { reference.Path = remap[floor.Id]; } else { reference.Path = string.Format("{0},{1}", lvbName, floor.Id); } } else { reference.Path = string.Format("{0},{1}", floor.FileName, floor.Id); } } output.WriteStructure(reference); } var tiles = new byte[level.Width * level.Height * 4]; // ReSharper disable UnusedVariable int offset = 0; // ReSharper restore UnusedVariable for (int i = 0, j = 0; i < level.Tiles.Length; i++, j += 4) { tiles[j + 0] = level.Tiles[i].BitsA; tiles[j + 0] &= 0x7F; tiles[j + 1] = 0; tiles[j + 2] = level.Tiles[i].BitsC; tiles[j + 3] = level.Tiles[i].BitsB; } using (var rle = new MemoryStream()) { rle.WriteRLE(tiles, 4, level.Tiles.Length, false); rle.Position = 0; output.WriteValueS32((int)rle.Length); output.WriteFromStream(rle, rle.Length); } foreach (var t in level.Entities) { output.WriteStructure(t); var obj = level.Objects[t.ObjectId]; var reference = new Map.BlobReference(); if (obj.FileName == null) { if (remap.ContainsKey(obj.Id) == true) { reference.Path = remap[obj.Id]; } else { reference.Path = string.Format("{0},{1}", lvbName, obj.Id); } } else { reference.Path = string.Format("{0},{1}", obj.FileName, obj.Id); } output.WriteStructure(reference); } } }