public BZNAOI(BZNReader reader)
        {
            IBZNToken tok;

            if (!reader.BinaryMode)
            {
                tok = reader.ReadToken();
                if (!tok.IsValidationOnly() || !tok.Validate("AOI")) throw new Exception("Failed to parse [AOI]");
            }

            tok = reader.ReadToken();
            if (!tok.Validate("undefptr", BinaryFieldType.DATA_PTR)) throw new Exception("Failed to parse undefptr/LONG");
            UInt32 undefptr = tok.GetUInt32H();

            tok = reader.ReadToken();
            if (!tok.Validate("team", BinaryFieldType.DATA_LONG)) throw new Exception("Failed to parse team/LONG");
            UInt32 team = tok.GetUInt32();

            tok = reader.ReadToken();
            if (!tok.Validate("interesting", BinaryFieldType.DATA_BOOL)) throw new Exception("Failed to parse interesting/BOOL");
            bool interesting = tok.GetBoolean();

            tok = reader.ReadToken();
            if (!tok.Validate("inside", BinaryFieldType.DATA_BOOL)) throw new Exception("Failed to parse inside/BOOL");
            bool inside = tok.GetBoolean();

            tok = reader.ReadToken();
            if (!tok.Validate("value", BinaryFieldType.DATA_LONG)) throw new Exception("Failed to parse value/LONG");
            UInt32 value = tok.GetUInt32();

            tok = reader.ReadToken();
            if (!tok.Validate("force", BinaryFieldType.DATA_LONG)) throw new Exception("Failed to parse force/LONG");
            UInt32 force = tok.GetUInt32();
        }
        public BZNAiPath(BZNReader reader)
        {
            IBZNToken tok;

            if (!reader.BinaryMode)
            {
                tok = reader.ReadToken();
                if (!tok.IsValidationOnly() || !tok.Validate("AiPath", BinaryFieldType.DATA_UNKNOWN)) throw new Exception("Failed to parse [AiPath]");
            }

            tok = reader.ReadToken();
            if (!tok.Validate("old_ptr", BinaryFieldType.DATA_VOID)) throw new Exception("Failed to parse old_ptr/VOID");
            old_ptr = tok.GetUInt32H();

            if (reader.N64)
            {
                tok = reader.ReadToken();
                uint pathValue = tok.GetUInt16();
                label = string.Format("bzn64path_{0:X4}", pathValue);
            }
            else
            {
                tok = reader.ReadToken();
                if (!tok.Validate("size", BinaryFieldType.DATA_LONG)) throw new Exception("Failed to parse size/LONG");
                UInt32 size = tok.GetUInt32();

                if (size > 0)
                {
                    tok = reader.ReadToken();
                    if (!tok.Validate("label", BinaryFieldType.DATA_CHAR)) throw new Exception("Failed to parse label/CHAR");
                    label = tok.GetString();
                }
            }

            tok = reader.ReadToken();
            if (!tok.Validate("pointCount", BinaryFieldType.DATA_LONG)) throw new Exception("Failed to parse pointCount/LONG");
            UInt32 pointCount = tok.GetUInt32();

            points = new Vector2D[pointCount];

            tok = reader.ReadToken();
            if (!tok.Validate("points", BinaryFieldType.DATA_VEC2D)) throw new Exception("Failed to parse points/VEC2D");
            for (int pointCounter = 0; pointCounter < pointCount; pointCounter++)
            {
                points[pointCounter] = tok.GetVector2D(pointCounter);
            }
            //UInt32 points = tok.GetUInt32();

            tok = reader.ReadToken();
            if (!tok.Validate("pathType", BinaryFieldType.DATA_VOID)) throw new Exception("Failed to parse pathType/VOID");
            pathType = tok.GetUInt32H();
        }
        public BZNGameObjectWrapper(BZNReader reader)
        {
            IBZNToken tok;
            if (!reader.BinaryMode)
            {
                tok = reader.ReadToken();
                if (!tok.IsValidationOnly() || !tok.Validate("GameObject", BinaryFieldType.DATA_UNKNOWN)) throw new Exception("Failed to parse [GameObject]");
            }

            if (reader.N64)
            {
                tok = reader.ReadToken();
                UInt16 ItemID = tok.GetUInt16();
                if (!BZNFile.BZn64IdMap.ContainsKey(ItemID)) throw new InvalidCastException(string.Format("Cannot convert n64 PrjID enumeration 0x(0:X2} to string PrjID", ItemID));
                PrjID = BZNFile.BZn64IdMap[ItemID];
            }
            else
            {
                tok = reader.ReadToken();
                if (!tok.Validate("PrjID", BinaryFieldType.DATA_ID)) throw new Exception("Failed to parse PrjID/ID");
                PrjID = tok.GetString();
            }

            tok = reader.ReadToken();
            if (!tok.Validate("seqno", BinaryFieldType.DATA_SHORT)) throw new Exception("Failed to parse seqno/SHORT");
            seqno = tok.GetUInt16();

            tok = reader.ReadToken();
            if (!tok.Validate("pos", BinaryFieldType.DATA_VEC3D)) throw new Exception("Failed to parse pos/VEC3D");
            pos = tok.GetVector3D();

            tok = reader.ReadToken();
            if (!tok.Validate("team", BinaryFieldType.DATA_LONG)) throw new Exception("Failed to parse team/LONG");
            team = tok.GetUInt32();

            tok = reader.ReadToken();
            if (reader.N64)
            {
                if (!tok.Validate("label", BinaryFieldType.DATA_SHORT)) throw new Exception("Failed to parse label/CHAR");
                label = string.Format("bzn64label_{0,4:X4}", tok.GetUInt16());
            }
            else
            {
                if (!tok.Validate("label", BinaryFieldType.DATA_CHAR)) throw new Exception("Failed to parse label/CHAR");
                label = tok.GetString();
            }

            tok = reader.ReadToken();
            if (!tok.Validate("isUser", BinaryFieldType.DATA_LONG)) throw new Exception("Failed to parse isUser/LONG");
            isUser = tok.GetUInt32();

            tok = reader.ReadToken();
            if (!tok.Validate("obj_addr", BinaryFieldType.DATA_PTR)) throw new Exception("Failed to parse obj_addr/PTR");
            obj_addr = tok.GetUInt32H();

            tok = reader.ReadToken();
            if (!tok.Validate("transform", BinaryFieldType.DATA_MAT3DOLD)) throw new Exception("Failed to parse transform/MAT3DOLD");
            transform = tok.GetMatrix();

            switch (BZNFile.ClassLabelMap[PrjID])
            {
                case "scrapsilo":
                    gameObject = new ClassScrapSilo(PrjID, isUser != 0);
                    break;
                case "wingman":
                case "turret":
                case "minelayer":
                case "sav":
                    gameObject = new ClassHoverCraft(PrjID, isUser != 0);
                    break;
                case "wpnpower":
                    gameObject = new ClassWeaponPowerup(PrjID, isUser != 0);
                    break;
                case "armory":
                    gameObject = new ClassArmory(PrjID, isUser != 0);
                    break;
                case "recycler":
                    gameObject = new ClassRecycler(PrjID, isUser != 0);
                    break;
                case "factory":
                    gameObject = new ClassFactory(PrjID, isUser != 0);
                    break;
                case "constructionrig":
                    gameObject = new ClassConstructionRig(PrjID, isUser != 0);
                    break;
                case "person":
                    gameObject = new ClassPerson(PrjID, isUser != 0);
                    break;
                case "apc":
                    gameObject = new ClassAPC(PrjID, isUser != 0);
                    break;
                case "scavenger":
                    gameObject = new ClassScavenger(PrjID, isUser != 0);
                    break;
                case "turrettank":
                    gameObject = new ClassTurretTank(PrjID, isUser != 0);
                    break;
                case "howitzer":
                    gameObject = new ClassHowitzer(PrjID, isUser != 0);
                    break;
                case "tug":
                    gameObject = new ClassTug(PrjID, isUser != 0);
                    break;
                case "walker":
                    gameObject = new ClassCraft(PrjID, isUser != 0);
                    break;
                default:
                    gameObject = new ClassGameObject(PrjID, isUser != 0);
                    break;
            }
            gameObject.LoadData(reader);
        }
        private BZNFile(Stream stream, bool inBinary = false, bool n64Data = false)
        {
            LoadMappings();

            BZNReader reader = new BZNReader(stream, inBinary, n64Data);

            //Console.WriteLine("Version: {0}", reader.Version);
            //Console.WriteLine("Platform: {0}", reader.N64 ? "N64" : "PC");
            //Console.WriteLine("Mode: {0}", reader.BinaryMode ? "BIN" : "ASCII");
            //Console.WriteLine();

            IBZNToken tok;

            this.Version = reader.Version;
            this.N64 = reader.N64;
            this.BinaryMode = reader.BinaryMode;

            if (reader.N64 || Version > 1022)
            {
                tok = reader.ReadToken();
                if (!tok.Validate("msn_filename", BinaryFieldType.DATA_CHAR)) throw new Exception("Failed to parse msn_filename");
                msn_filename = tok.GetString();
            }

            //Console.WriteLine("msn_filename: \"{0}\"", msn_filename);

            if (!reader.N64)
            {
                tok = reader.ReadToken();
                if (!tok.Validate("seq_count", BinaryFieldType.DATA_LONG)) throw new Exception("Failed to parse seq_count/LONG");
                seq_count = tok.GetInt32();

                tok = reader.ReadToken();
                if (!tok.Validate("missionSave", BinaryFieldType.DATA_BOOL)) throw new Exception("Failed to parse missionSave/BOOL");
                missionSave = tok.GetBoolean();

                tok = reader.ReadToken();
                if (!tok.Validate("TerrainName", BinaryFieldType.DATA_CHAR)) throw new Exception("Failed to parse TerrainName/CHAR");
                TerrainName = tok.GetString();

                //Console.WriteLine("seq_count: {0}", seq_count);
                //Console.WriteLine("missionSave: {0}", missionSave);
                //Console.WriteLine("TerrainName: {0}", TerrainName);
                //Console.WriteLine();
            }
            else
            {
                missionSave = true;
                TerrainName = "UNKNOWN_BZn64";
            }

            tok = reader.ReadToken();
            if (!tok.Validate("size", BinaryFieldType.DATA_LONG)) throw new Exception("Failed to parse count/LONG");
            Int32 CountItems = tok.GetInt32();

            //Console.WriteLine("Game Objects\tCount: {0}", CountItems);

            GameObjects = new BZNGameObjectWrapper[CountItems];

            for (int gameObjectCounter = 0; gameObjectCounter < CountItems; gameObjectCounter++)
            {
                GameObjects[gameObjectCounter] = new BZNGameObjectWrapper(reader);
                //Console.WriteLine("{0}\t{1}", GameObjects[gameObjectCounter].seqno, GameObjects[gameObjectCounter].PrjID);
            }

            if (N64)
            {
                seq_count = GameObjects.Max(dr => dr.seqno) + 1;
            }

            //foreach(BZNGameObjectWrapper obj in GameObjects)
            //{
            //    string type = obj.gameObject.GetType().Name.Substring(3);
            //    if (type == "GameObject") type += "?";
            //
            //    Console.WriteLine(
            //        "{0}  {1}  {2}  [{3,6:F2}, {4,6:F2}, {5,9:F2}]",
            //        obj.seqno.ToString().PadLeft(4),
            //        obj.PrjID.PadRight(12),
            //        type.PadRight(16),
            //        obj.pos.x,
            //        obj.pos.y,
            //        obj.pos.z
            //    );
            //}

            //Console.WriteLine();

            tok = reader.ReadToken();
            if (reader.N64)
            {
                if (!tok.Validate("name", BinaryFieldType.DATA_CHAR)) throw new Exception("Failed to parse name/CHAR");
                MissionClass = string.Format("BZn64Mission_{0,4:X4}", tok.GetUInt16());
            }
            else
            {
                if (!tok.Validate("name", BinaryFieldType.DATA_CHAR)) throw new Exception("Failed to parse name/CHAR");
                MissionClass = tok.GetString();
            }

            //Console.WriteLine("MissionClass: \"{0}\"", MissionClass);

            tok = reader.ReadToken();
            if (!tok.Validate("sObject", BinaryFieldType.DATA_PTR)) throw new Exception("Failed to parse sObject/PTR");
            sObject = tok.GetUInt32H();

            //Console.WriteLine("sObject: {0:X8}", sObject);

            //Console.WriteLine();

            if (!reader.BinaryMode)
            {
                tok = reader.ReadToken();
                if (!tok.IsValidationOnly() || !tok.Validate("AiMission")) throw new Exception("Failed to parse [AiMission]");
            }
            /////////////////////////////////////
            if (!reader.BinaryMode)
            {
                tok = reader.ReadToken();
                if (!tok.IsValidationOnly() || !tok.Validate("AOIs")) throw new Exception("Failed to parse [AOIs]");
            }

            tok = reader.ReadToken();
            if (!tok.Validate("size", BinaryFieldType.DATA_LONG)) throw new Exception("Failed to parse size/LONG");
            Int32 CountAOIs = tok.GetInt32();

            //Console.WriteLine("AOI\tCount: {0}", CountAOIs);

            AOIs = new BZNAOI[CountAOIs];

            for (int aoiCounter = 0; aoiCounter < CountAOIs; aoiCounter++)
            {
                AOIs[aoiCounter] = new BZNAOI(reader);

                //Console.WriteLine("{0:X8}\tTeam: {1}\tInteresting: {2}\tInside: {3}\tValue: {4}\tForce: {5}", undefptr, team.ToString().PadLeft(2), interesting, inside, value, force);
            }

            //Console.WriteLine();

            /////////////////////////////////////
            if (!reader.BinaryMode)
            {
                tok = reader.ReadToken();
                if (!tok.IsValidationOnly() || !tok.Validate("AiPaths", BinaryFieldType.DATA_UNKNOWN)) throw new Exception("Failed to parse [AiPaths]");
            }

            tok = reader.ReadToken();
            if (!tok.Validate("count", BinaryFieldType.DATA_LONG)) throw new Exception("Failed to parse count/LONG");
            Int32 CountAiPaths = tok.GetInt32();

            //Console.WriteLine("AiPath\tCount: {0}", CountAiPaths);

            AiPaths = new BZNAiPath[CountAiPaths];

            for (int AiPathCounter = 0; AiPathCounter < CountAiPaths; AiPathCounter++)
            {
                AiPaths[AiPathCounter] = new BZNAiPath(reader);

                //Console.WriteLine("OldPtr: {0:X8}\tPathType: {1}\tLabel: {2}", old_ptr, pathType, label);
                //for (int pointCounter = 0; pointCounter < pointCount; pointCounter++)
                //{
                //    Console.WriteLine("\t[{0,2}] {1,8:F2}, {2,8:F2}", pointCounter, points[pointCounter].x, points[pointCounter].z);
                //}
            }

            //if ((tok = reader.ReadToken()) != null)
            //{
            //    Console.WriteLine("UNKNOWN DATA");
            //    do
            //    {
            //        if (tok.IsValidationOnly())
            //        {
            //            Console.WriteLine(tok.ToString());
            //        }
            //        else
            //        {
            //            Console.Write(tok.ToString());
            //            try
            //            {
            //                Console.Write("\t" + tok.GetString());
            //            }
            //            catch { }
            //            Console.WriteLine();
            //        }
            //        //Console.ReadKey(true);
            //    } while ((tok = reader.ReadToken()) != null);
            //}
        }