Askeladd Posted March 14, 2017 Share Posted March 14, 2017 Hi guys. I want to read RA1 map files and I can decode the MapPack section just fine, however when reading for example scg01ea.ini (first Allied mission) I am encountering several (template id, template tile index) entries where the index is set to 255 rather than a valid index (0, 1, 2, etc). Yet the map displays fine in the game and RAED. How do they handle this? I'm positive my code is correct and I couldn't find an answer digging through the OpenRA, openredalert, etc, source codes. Here is the relevant code just in case (C#): private static TerrainTile[] ReadMapPack(IOrderedDictionary mappack) { var sb = new StringBuilder(); for (int i = 0; i < mappack.Count; i++) sb.Append(mappack[i] as string); var bin = Convert.FromBase64String(sb.ToString()); var br = new BinaryReader(new MemoryStream(bin)); var mapdata = new byte[3 * Constants.MapCells]; int mdcnt = 0; while(mdcnt < mapdata.Length) { int cmpsz = br.ReadUInt16(); // compressed size int ucmpsz = br.ReadUInt16(); // uncompressed size var chunk = br.ReadBytes(cmpsz); Format80.Decode(chunk, 0, mapdata, mdcnt, cmpsz); mdcnt += ucmpsz; } var terrain = new TerrainTile[Constants.MapCells]; var tmpids = new ushort[Constants.MapCells]; br = new BinaryReader(new MemoryStream(mapdata)); for (int i = 0; i < Constants.MapCells; i++) tmpids[i] = br.ReadUInt16(); for (int i = 0; i < Constants.MapCells; i++) terrain[i] = new TerrainTile(tmpids[i], br.ReadByte()); return terrain; } Link to comment Share on other sites More sharing options...
Askeladd Posted March 15, 2017 Author Share Posted March 15, 2017 Nevermind, I figured it out. The mistake was in the Format80 decoder. I added an argument to specify the start of the destination buffer but forgot to take that offset into account in the algorithm. D'oh XD Link to comment Share on other sites More sharing options...
Nyerguds Posted March 15, 2017 Share Posted March 15, 2017 IOrderedDictionary? Odd choice, not even using a generic type for that. I'd expect at least OrderedDictionary<String> for type safety. But really, just List<String> or bare String[] array will do the job. I mean, from the moment it implements IEnumerable<String>, and you got Linq, you can just do String.Join(String.Empty, mappack.ToArray()) to get the full string in one operation, without needing that StringBuilder. By the way, BinaryReader and Stream classes are IDisposable, so they should always be used in a using() {...} block to ensure they are cleaned up correctly, to avoid memory leaks. Link to comment Share on other sites More sharing options...
Askeladd Posted March 15, 2017 Author Share Posted March 15, 2017 I'm using OrderedDictionary because I want to take care of double tag keys and I want to preserve the order of the tags. There is no built-in generic version of it which is annoying, so I wrote one myself yesterday. Thanks for the tips. There are several ways to do things in C#, but I know what I'm doing. Link to comment Share on other sites More sharing options...
Nyerguds Posted March 15, 2017 Share Posted March 15, 2017 Ah, indeed, it has no generic version. That is a pity. Yeah, OrderedDictionary gives a quick way of sorting ini data, I guess, though if you go through all keys and just dump them in the dictionary by (key int, line text) without further checks, the data for each key would be the last data line found for that key, whereas the game always takes the first occurrence of a key when doing ini reads. So while it does solve the potential problem of duplicate keys, it won't do it in the way the game would, unless you do a specific check that only fills up the index if it's still blank. (i reality, I do think that encountering duplicate keys is probably a sign the whole section is corrupted, though ) Link to comment Share on other sites More sharing options...
Nyerguds Posted March 22, 2017 Share Posted March 22, 2017 tomsons26 wanted me to inform the world that "format80" is actually called "LCW"; Lempel-Castle-Welch compression (Louis Castle's own tweaked LZW compression) https://forums.cncnet.org/index.php?topic=4403.0 Link to comment Share on other sites More sharing options...
Iran Posted March 24, 2017 Share Posted March 24, 2017 check my code https://github.com/Iran/RAFullMapPreviewGenerator Link to comment Share on other sites More sharing options...
Blade Posted April 27, 2017 Share Posted April 27, 2017 Regarding values of 0x00FF for the tile id, those should be treated the same as 0xFFFF, ie clear randomised tiles. This means that tileset 255, which is a floor arrow in the interior theater is not valid and should never be displayed, it should be the black clear tile instead. This is the way RA itself treats tiles and is probably related to the game originally handling old c&c map data during development. Link to comment Share on other sites More sharing options...
Nyerguds Posted April 28, 2017 Share Posted April 28, 2017 Yeah, bytes FF 00 are the indicator for clear terrain in C&C1, so I guess tileset id "FF" remains reserved because of that. Though XCC annoyingly writes the actual auto-distributed clear terrain tiles (tile ID 00, tiles 00-0F) to the map, and CCMap uses bytes FF FF for some bizarre reason (which is annoying for my N64 converter since it's the same thing the N64 format uses, meaning it can no longer be used for quick type detection). Why would they assign that to an actual tile though? Couldn't just put a dummy in there, or plain skip it? Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now