• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Parsing the .dat file automatically (C#)

TGYoshi

In space
Joined
Aug 20, 2010
Messages
1,107
Reaction score
121
Location
In space
I'm trying to parse a .dat file, but it goes wrong [somewhere].
I've also compared my code with RME's sources and somewhat copy-pasted a whole bunch of it, yet it still messes up.

(yeye huge mess below)
PHP:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Drawing;

namespace SpellCreator
{
	static class SpritesIO
	{

		public static Dictionary<int, List<Image>> images = new Dictionary<int, List<Image>>();
		public static void LoadAreaSprites(string file)
		{
			FileStream fs = new FileStream("Tibia.dat", FileMode.Open);
			BinaryReader r = new BinaryReader(fs);
			try
			{
				Out("Version:   " + r.ReadUInt32());
				int items = r.ReadUInt16();
				Out("Items:     " + items);
				int outfits = r.ReadUInt16();
				Out("Outfits:   " + outfits);
				int effects = r.ReadUInt16();
				Out("Effects:   " + effects);
				int deffects = r.ReadUInt16();
				Out("D.Effects: " + deffects);

				int bitsLeft = items;
				string leaching = "Items";

				for (int id = 100; id <= items + outfits + effects + deffects - 100; id++)
				{
					bool cont = true;
					while (true)   // READ FLAGS (actually just ignore all :P)
					{
						byte by = r.ReadByte();
						switch (by)
						{
							case 0x00: //is groundtile
								//r.ReadUInt16(); // speed modifier
								//speed = read_short;
								//sType->speed = speed;
								//sType->group = ITEM_GROUP_GROUND;
								break;
							case 0x01: //all OnTop
								//sType->alwaysOnTop = true;
								//sType->alwaysOnTopOrder = 1;
								break;
							case 0x02: //can walk through
								//sType->alwaysOnTop = true;
								//sType->alwaysOnTopOrder = 2;
								break;
							case 0x03: //can walk through
								//sType->alwaysOnTop = true;
								//sType->alwaysOnTopOrder = 3;
								break;
							case 0x04: //is a container
								//sType->group = ITEM_GROUP_CONTAINER;
								break;
							case 0x05: //is stackable
								//sType->stackable = true;
								break;
							case 0x06: //ladders
								break;
							case 0x07: //is useable
								//sType->useable = true;
								break;
							case 0x08: //runes
								//sType->group = ITEM_GROUP_RUNE;
								break;
							case 0x09: //writeable objects
								//sType->group = ITEM_GROUP_WRITEABLE;
								//sType->readable = true;
								r.ReadUInt16();
								//file.getU16(); //maximum text length?
								break;
							case 0x0A: //writeable objects that can't be edited
								//sType->readable = true;
								r.ReadUInt16();
								//file.getU16(); //maximum text length?
								break;
							case 0x0B: //can contain fluids
								//sType->group = ITEM_GROUP_FLUID;
								break;
							case 0x0C: //liquid with states
								//sType->group = ITEM_GROUP_SPLASH;
								break;
							case 0x0D: //is blocking
								//sType->blockSolid = true;
								break;
							case 0x0E: //is not moveable
								//sType->moveable = false;
								break;
							case 0x0F: //blocks missiles (walls, magic wall etc)
								//sType->blockProjectile = true;
								break;
							case 0x10: //blocks monster movement (flowers, parcels etc)
								//sType->blockPathFind = true;
								break;
							case 0x11: //can be equipped
								//sType->pickupable = true;
								break;
							case 0x12: //wall items
								//sType->isHangable = true;
								break;
							case 0x13:
								//sType->isHorizontal = true;
								break;
							case 0x14:
								//sType->isVertical = true;
								break;
							case 0x15: //rotateable items
								//sType->rotateable = true;
								break;
							case 0x16: //light info ..
								r.ReadUInt16();
								r.ReadUInt16();
								//file.getU16(); // level
								//file.getU16(); // color
								//sType->lightColor = lightcolor;
								break;
							case 0x17: // No object has this...
								break;
							case 0x18: //floor change down
								break;
							case 0x19:
								{ //Draw offset
									r.ReadUInt16();
									r.ReadUInt16();
								} break;
							case 0x1A:
								{
									r.ReadUInt16();
								} break;
							case 0x1B://draw with height offset for all parts (2x2) of the sprite
								break;
							case 0x1C: // offset life-bar (for larger monsters)
								break;
							case 0x1D:
								{ // Minimap color
									//r.ReadUInt16();
								} break;
							case 0x1E:
								{// Floor change?
									r.ReadByte();
									r.ReadByte();
									//file.getByte(); // 86 -> openable holes, 77-> can be used to go down, 76 can be used to go up, 82 -> stairs up, 79 switch,
									//file.getByte(); // always 4
								} break;
							case 0x1F:
								break;
							case 0x20: // LookThrough
								break;
							case 0xFF:
								// READ OBJECT INFO
								System.Windows.Forms.MessageBox.Show("Read data");
								int w = (int)r.ReadByte();
								int h = (int)r.ReadByte();
								Out("W/H: " + w + "/" + h);
								if (w > 1 || h > 1)
									r.ReadByte();
								int bf = (int)r.ReadByte();
								int dx = (int)r.ReadByte();
								int dy = (int)r.ReadByte();
								int dz = (int)r.ReadByte();
								int a = (int)r.ReadByte();
								//if (w > 2 || h > 2)
								//	System.Windows.Forms.MessageBox.Show("out: "+h.ToString()+"-"+w.ToString()+" on "+id.ToString());
								if (leaching == "Effects")
								{
									List<Image> b = new List<Image>();
									for (int s = 0; s < (dx * dy * dz * w * h * a * bf); s++)
									{
										// Handle sprite...
										b.Add(GetSpriteImage("Tibia.spr", r.ReadUInt16()));
									}
									images.Add(id, b);
								}
								//spr.Save("temp\\s_" + id + "_total.gif", System.Drawing.Imaging.ImageFormat.Gif);
								//System.Windows.Forms.MessageBox.Show("Reading finished; " + id);
								cont = false;
								bitsLeft--;
								if (bitsLeft == 0)
								{
									System.Windows.Forms.MessageBox.Show("From:" +leaching);
									switch (leaching)
									{
										case "Items":
											leaching = "Outfits";
											bitsLeft = outfits;
											break;
										case "Outfits":
											leaching = "Effects";
											bitsLeft = effects;
											break;
										case "Effects":
											leaching = "Deffects";
											bitsLeft = deffects;
											break;
										case "Deffects":
											return;
									}
								}
								break;
							default:
								System.Windows.Forms.MessageBox.Show("Unknown byte. (parsing "+id+") => "+by.ToString());
								break;
						}
						if (!cont)
							break;
					}

				}
			}
			catch (Exception ex)
			{
				// just bail out
				System.Windows.Forms.MessageBox.Show("Unable to read DAT: "+ex.Message);
			}
			finally
			{
				r.Close();
				fs.Close();
			}
		}

		public static Image GetSpriteImage(string file, int spriteId)	// From TibiaAPI
		{
			//if (spriteId < 2)// || spriteId > 28722)
			//	throw new ArgumentOutOfRangeException("spriteId");

			int size = 32;
			Bitmap bitmap = new Bitmap(size, size);
			if (spriteId < 2)
				return bitmap;

			using (BinaryReader reader = new BinaryReader(File.OpenRead(file)))
			{
				try
				{
					ushort currentPixel = 0;
					long targetOffset;

					reader.BaseStream.Seek(6 + (spriteId - 1) * 4, SeekOrigin.Begin);
					reader.BaseStream.Seek(reader.ReadUInt32() + 3, SeekOrigin.Begin);

					targetOffset = reader.BaseStream.Position + reader.ReadUInt16();

					while (reader.BaseStream.Position < targetOffset)
					{
						ushort transparentPixels = reader.ReadUInt16();
						ushort coloredPixels = reader.ReadUInt16();
						currentPixel += transparentPixels;
						for (int i = 0; i < coloredPixels; i++)
						{
							bitmap.SetPixel(
								currentPixel % size,
								currentPixel / size,
								Color.FromArgb(reader.ReadByte(), reader.ReadByte(), reader.ReadByte())
							);
							currentPixel++;
						}
					}
				}
				catch {}
			}

			return bitmap;
		}
	}
}

It just messes up while reading the bytes.
About 2394712389523457812345789 popups that a certain byte is unknown;

Code:
---------------------------

---------------------------
Unknown byte. (parsing 100) => 138
---------------------------
OK   
---------------------------

So I basically conclude I'm missing some bit of parsing.
Loading the version and items/outfits etc. count works correctly.

Weird, however, is that whenever I just ignore everything that goes wrong, I get some kind of successful sprite output. However, several sprites are missing, the numbers are incorrect, etc.

Anyone has any idea what might be wrong?
 
Back
Top