Jump to content
Sign in to follow this  
Askeladd

Question about templates in MapPack section

Recommended Posts

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;
}

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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 :P)

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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?

Share this post


Link to post
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×