using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TC = System.ComponentModel.TypeConverterAttribute;
using EXP = System.ComponentModel.ExpandableObjectConverter;
using SharpDX;
using System.Xml;
using System.Text.RegularExpressions;




/*

Parts of this are adapted from CamxxCore's RageAudioTool, although it's been completely reworked for CW.
-dexyfex


https://github.com/CamxxCore/RageAudioTool

MIT License

Copyright (c) 2017 Cameron Berry

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

*/



namespace CodeWalker.GameFiles
{
    public enum RelDatFileType : uint
    {
        Dat4 = 4,
        Dat10ModularSynth = 10,
        Dat15DynamicMixer = 15,
        Dat16Curves = 16,
        Dat22Categories = 22,
        Dat54DataEntries = 54,
        Dat149 = 149,
        Dat150 = 150,
        Dat151 = 151
    }

    [TC(typeof(EXP))] public class RelFile : GameFile, PackedFile
    {
        public byte[] RawFileData { get; set; }
        public RelDatFileType RelType { get; set; }
        public uint DataLength { get; set; }
        public byte[] DataBlock { get; set; }
        public uint DataUnkVal { get; set; }
        public uint NameTableLength { get; set; }
        public uint NameTableCount { get; set; }
        public uint[] NameTableOffsets { get; set; }
        public string[] NameTable { get; set; }
        public uint IndexCount { get; set; }
        public uint IndexStringFlags { get; set; } = 2524;
        public RelIndexHash[] IndexHashes { get; set; }
        public RelIndexString[] IndexStrings { get; set; }
        public uint HashTableCount { get; set; }
        public uint[] HashTableOffsets { get; set; }
        public MetaHash[] HashTable { get; set; }
        public uint PackTableCount { get; set; }
        public uint[] PackTableOffsets { get; set; }
        public MetaHash[] PackTable { get; set; }

        public RelData[] RelDatas { get; set; }
        public RelData[] RelDatasSorted { get; set; }
        public Dictionary<uint, RelData> RelDataDict { get; set; } = new Dictionary<uint, RelData>();

        public bool IsAudioConfig { get; set; }


        //fields used by the editor:
        public bool HasChanged { get; set; } = false;
        public List<string> SaveWarnings = null;


        public RelFile() : base(null, GameFileType.Rel)
        {
        }
        public RelFile(RpfFileEntry entry) : base(entry, GameFileType.Rel)
        {
            RpfFileEntry = entry;
        }

        public void Load(byte[] data, RpfFileEntry entry)
        {
            RawFileData = data;
            if (entry != null)
            {
                RpfFileEntry = entry;
                Name = entry.Name;
            }

            MemoryStream ms = new MemoryStream(data);
            BinaryReader br = new BinaryReader(ms);
            StringBuilder sb = new StringBuilder();

            RelType = (RelDatFileType)br.ReadUInt32(); //type

            DataLength = br.ReadUInt32(); //length of data block
            DataBlock = br.ReadBytes((int)DataLength); //main data block...

            NameTableLength = br.ReadUInt32(); //length of this nametable block
            NameTableCount = br.ReadUInt32();
            if (NameTableCount > 0)
            {
                uint[] ntoffsets = new uint[NameTableCount]; //string offsets
                for (uint i = 0; i < NameTableCount; i++)
                {
                    ntoffsets[i] = br.ReadUInt32();
                }
                NameTableOffsets = ntoffsets;
                string[] names = new string[NameTableCount];
                for (uint i = 0; i < NameTableCount; i++)
                {
                    sb.Clear();
                    while (true)
                    {
                        char c = (char)br.ReadByte();
                        if (c != 0) sb.Append(c);
                        else break;
                    }
                    names[i] = sb.ToString();

                    //JenkIndex.Ensure(names[i]); //really need both here..?
                    JenkIndex.Ensure(names[i].ToLowerInvariant());
                }
                NameTable = names;
            }

            IndexCount = br.ReadUInt32(); //count of index items
            if (IndexCount > 0)
            {
                if ((RelType == RelDatFileType.Dat4) && (NameTableLength == 4))//audioconfig.dat4.rel    //checking NameTableLength here doesn't make sense!
                {
                    IsAudioConfig = true;
                    IndexStringFlags = br.ReadUInt32(); //what is this?  2524
                    if (IndexStringFlags != 2524)
                    { }
                    RelIndexString[] indexstrs = new RelIndexString[IndexCount];
                    for (uint i = 0; i < IndexCount; i++)
                    {
                        byte sl = br.ReadByte();
                        sb.Clear();
                        for (int j = 0; j < sl; j++)
                        {
                            char c = (char)br.ReadByte();
                            if (c != 0) sb.Append(c);
                        }
                        RelIndexString ristr = new RelIndexString();
                        ristr.Name = sb.ToString();
                        ristr.Offset = br.ReadUInt32();
                        ristr.Length = br.ReadUInt32();
                        indexstrs[i] = ristr;
                        JenkIndex.Ensure(ristr.Name.ToLowerInvariant());
                    }
                    IndexStrings = indexstrs;
                }
                else //for all other .rel files...
                {
                    RelIndexHash[] indexhashes = new RelIndexHash[IndexCount];
                    for (uint i = 0; i < IndexCount; i++)
                    {
                        RelIndexHash rihash = new RelIndexHash();
                        rihash.Name = new MetaHash(br.ReadUInt32());
                        rihash.Offset = br.ReadUInt32();
                        rihash.Length = br.ReadUInt32();
                        indexhashes[i] = rihash;
                    }
                    IndexHashes = indexhashes;
                }
            }


            HashTableCount = br.ReadUInt32();
            if (HashTableCount != 0)
            {
                uint[] htoffsets = new uint[HashTableCount];
                MetaHash[] hthashes = new MetaHash[HashTableCount];
                for (uint i = 0; i < HashTableCount; i++)
                {
                    htoffsets[i] = br.ReadUInt32();

                    var pos = ms.Position;
                    ms.Position = htoffsets[i];
                    hthashes[i] = new MetaHash(br.ReadUInt32());
                    ms.Position = pos;
                }
                HashTableOffsets = htoffsets;
                HashTable = hthashes;
            }

            PackTableCount = br.ReadUInt32();
            if (PackTableCount != 0)
            {
                uint[] ptoffsets = new uint[PackTableCount];
                MetaHash[] pthashes = new MetaHash[PackTableCount];
                for (uint i = 0; i < PackTableCount; i++)
                {
                    ptoffsets[i] = br.ReadUInt32();

                    var pos = ms.Position;
                    ms.Position = ptoffsets[i];
                    pthashes[i] = new MetaHash(br.ReadUInt32());
                    ms.Position = pos;
                }
                PackTableOffsets = ptoffsets;
                PackTable = pthashes;
            }

            if (ms.Position != ms.Length)
            { }
            //EOF!

            br.Dispose();
            ms.Dispose();


            ParseDataBlock();

            //BuildHashMaps();


            Loaded = true;
        }


        private void ParseDataBlock()
        {



            MemoryStream ms = new MemoryStream(DataBlock);
            BinaryReader br = new BinaryReader(ms);

            DataUnkVal = br.ReadUInt32(); //3 bytes used... for? ..version? flags?
            #region DataUnkVal unk values test
            //switch (DataUnkVal)
            //{
            //    case 5252715: //dlcbusiness_amp.dat10.rel
            //    case 5301323: //dlcbeach_game.dat149.rel
            //    case 5378673: //dlcmpheist_game.dat150.rel
            //    case 5750395: //dlcbeach_game.dat150.rel
            //    case 6353778: //dlcbeach_game.dat151.rel
            //    case 6894089: //dlcpilotschool_game.dat151.rel
            //    case 6978435: //dlcxmas2_amp.dat10.rel
            //    case 7126027: //audioconfig.dat4.rel
            //    case 7314721: //dlcmpheist_amp.dat10.rel
            //    case 7516460: //dlcpd03_game.dat151.rel
            //    case 7917027: //dlcluxe_amp.dat10.rel
            //    case 7921508: //dlcluxe_game.dat151.rel
            //    case 8149475: //dlcluxe2_amp.dat10.rel
            //    case 8751734: //dlcsfx1_game.dat151.rel
            //    case 9028036: //dlchalloween_amp.dat10.rel
            //    case 9037528: //dlclowrider_amp.dat10.rel
            //    case 9458585: //dlcapartment_amp.dat10.rel
            //    case 9486222: //dlcapartment_mix.dat15.rel
            //    case 9806108: //mpvalentines2_amp.dat10.rel
            //    case 9813679: //dlcjanuary2016_amp.dat10.rel
            //    case 10269543://dlclow2_amp.dat10.rel
            //    case 10891463://dlcexec1_amp.dat10.rel
            //    case 11171338://dlcstunt_amp.dat10.rel
            //    case 11918985://dlcbiker_amp.dat10.rel
            //    case 12470522://dlcimportexport_amp.dat10.rel
            //    case 12974726://audioconfig.dat4.rel
            //    case 13117164://dlcspecialraces_amp.dat10.rel
            //        break;
            //    default:
            //        break;
            //}
            #endregion


            List<RelData> reldatas = new List<RelData>();
            if (IndexHashes != null)
            {
                foreach (var indexhash in IndexHashes)
                {
                    reldatas.Add(ReadRelData(br, indexhash));
                }
            }
            else if (IndexStrings != null)
            {
                foreach (var indexstr in IndexStrings)
                {
                    reldatas.Add(ReadRelData(br, indexstr));
                }
            }
            RelDatas = reldatas.ToArray();

            reldatas.Sort((d1, d2) => d1.DataOffset.CompareTo(d2.DataOffset));
            RelDatasSorted = reldatas.ToArray();


            br.Dispose();
            ms.Dispose();




            RelDataDict.Clear();
            foreach (var reldata in RelDatas)
            {
                if ((reldata.NameHash == 0) && !string.IsNullOrEmpty(reldata.Name))
                {
                    reldata.NameHash = JenkHash.GenHash(reldata.Name); //should this be lower case?
                    JenkIndex.Ensure(reldata.Name);
                    JenkIndex.Ensure(reldata.Name.ToLowerInvariant()); //which one to use?
                }

                //if (reldata.NameHash == 0)
                //{ }//no hits here
                //if (RelDataDict.ContainsKey(reldata.NameHash))
                //{ }//no hits here

                RelDataDict[reldata.NameHash] = reldata;
            }
            foreach (var reldata in RelDatas)
            {
                RelSound snd = reldata as RelSound;
                if (snd != null)
                {
                    if (snd.ChildSoundsCount > 0)
                    {
                        snd.ChildSounds = new RelData[snd.ChildSoundsCount];
                        for (int i = 0; i < snd.ChildSoundsCount; i++)
                        {
                            var audhash = snd.ChildSoundsHashes[i];
                            RelData auddata = null;
                            if (RelDataDict.TryGetValue(audhash, out auddata))
                            {
                                snd.ChildSounds[i] = auddata;
                            }
                            else
                            { }
                        }
                    }
                    if (snd.AudioContainers != null)
                    {
                        foreach (var cnt in snd.AudioContainers)
                        {
                            string cname = JenkIndex.TryGetString(cnt.Hash);
                            if (!string.IsNullOrEmpty(cname))
                            { }
                            else
                            { }
                        }
                    }
                }
            }


            if ((RelType == RelDatFileType.Dat4) && (!IsAudioConfig))
            {
                //speech.dat4.rel

                var speechDict = new Dictionary<uint, Dat4SpeechData>();
                foreach (var reldata in RelDatasSorted)
                {
                    var speechData = reldata as Dat4SpeechData;
                    if (speechData != null)
                    {
                        speechDict[speechData.DataOffset] = speechData;
                    }
                    else
                    { }

                    speechData.Type = Dat4SpeechType.ByteArray;
                    speechData.TypeID = 0; //will be set again after this

                }
                for (uint i = 0; i < HashTableCount; i++)
                {
                    var hashOffset = HashTableOffsets[i];
                    var hash = HashTable[i];
                    var itemOffset = hashOffset - 8;
                    Dat4SpeechData speechData = null;
                    speechDict.TryGetValue(itemOffset, out speechData);
                    if (speechData != null)
                    {
                        speechData.Type = Dat4SpeechType.Hash;
                        speechData.TypeID = 4;
                        speechData.Hash = hash;
                    }
                    else
                    { }
                }
                for (uint i = 0; i < PackTableCount; i++)
                {
                    var packOffset = PackTableOffsets[i];
                    var pack = PackTable[i];
                    var itemOffset = packOffset - 12;
                    Dat4SpeechData speechData = null;
                    speechDict.TryGetValue(itemOffset, out speechData);
                    if (speechData != null)
                    {
                        speechData.Type = Dat4SpeechType.Container;
                        speechData.TypeID = 8;
                        speechData.ContainerHash = pack;
                    }
                    else
                    { }//shouldn't happen!
                }


            }


        }




        private RelData ReadRelData(BinaryReader br, RelIndexHash h)
        {
            return ReadRelData(br, null, h.Name, h.Offset, h.Length);
        }
        private RelData ReadRelData(BinaryReader br, RelIndexString s)
        {
            return ReadRelData(br, s.Name, JenkHash.GenHash(s.Name.ToLowerInvariant()), s.Offset, s.Length);
        }
        private RelData ReadRelData(BinaryReader br, string name, MetaHash hash, uint offset, uint length)
        {
            br.BaseStream.Position = offset;
            byte[] data = br.ReadBytes((int)length);


            RelData d = new RelData(this); //use this base object to construct the derived one...
            d.Name = name;
            d.NameHash = hash;
            d.DataOffset = offset;
            d.DataLength = length;
            d.Data = data;


            using (BinaryReader dbr = new BinaryReader(new MemoryStream(data)))
            {
                d.ReadType(dbr);

                switch (RelType)
                {
                    case RelDatFileType.Dat4:   //speech.dat4.rel, audioconfig.dat4.rel
                        return ReadData4(d, dbr);
                    case RelDatFileType.Dat10ModularSynth:  //amp.dat10.rel
                        return ReadData10(d, dbr);
                    case RelDatFileType.Dat15DynamicMixer:  //mix.dat15.rel
                        return ReadData15(d, dbr);
                    case RelDatFileType.Dat16Curves:  //curves.dat16.rel
                        return ReadData16(d, dbr);
                    case RelDatFileType.Dat22Categories:  //categories.dat22.rel
                        return ReadData22(d, dbr);
                    case RelDatFileType.Dat54DataEntries:  //sounds.dat54.rel
                        return ReadData54(d, dbr);
                    case RelDatFileType.Dat149: //game.dat149.rel
                        return ReadData149(d, dbr);
                    case RelDatFileType.Dat150: //game.dat150.rel
                        return ReadData150(d, dbr);
                    case RelDatFileType.Dat151: //game.dat151.rel
                        return ReadData151(d, dbr);
                    default:
                        return d; //shouldn't get here...
                }
            }
        }



        private RelData ReadData4(RelData d, BinaryReader br)
        {
            if (IsAudioConfig) //(for audioconfig.dat4.rel)
            {
                switch ((Dat4ConfigType)d.TypeID)
                {
                    case Dat4ConfigType.Int: return new Dat4ConfigInt(d, br);
                    case Dat4ConfigType.Int2: return new Dat4ConfigInt2(d, br);
                    case Dat4ConfigType.Float: return new Dat4ConfigFloat(d, br);
                    case Dat4ConfigType.String: return new Dat4ConfigString(d, br);
                    case Dat4ConfigType.Orientation: return new Dat4ConfigOrientation(d, br);
                    case Dat4ConfigType.VariableList: return new Dat4ConfigVariableList(d, br);
                    case Dat4ConfigType.WaveSlot: return new Dat4ConfigWaveSlot(d, br);
                    case Dat4ConfigType.WaveSlotsList: return new Dat4ConfigWaveSlotsList(d, br);
                    case Dat4ConfigType.UnkER: return new Dat4ConfigUnkER(d, br);
                    default:
                        break;
                }
            }
            else //(for eg speech.dat4.rel)
            {
                return new Dat4SpeechData(d, br);
            }
            return d;
        }
        private RelData ReadData10(RelData d, BinaryReader br)
        {
            switch ((Dat10RelType)d.TypeID)
            {
                case Dat10RelType.SynthPreset: return new Dat10SynthPreset(d, br);
                case Dat10RelType.Synth: return new Dat10Synth(d, br);
                default:
                    break;
            }

            return d;
        }
        private RelData ReadData15(RelData d, BinaryReader br)
        {
            switch ((Dat15RelType)d.TypeID)
            {
                case Dat15RelType.Patch: return new Dat15Patch(d, br);
                case Dat15RelType.Unk1: return new Dat15Unk1(d, br);
                case Dat15RelType.Scene: return new Dat15Scene(d, br);
                case Dat15RelType.Group: return new Dat15Group(d, br);
                case Dat15RelType.GroupList: return new Dat15GroupList(d, br);
                case Dat15RelType.Unk5: return new Dat15Unk5(d, br);
                case Dat15RelType.Unk6: return new Dat15Unk6(d, br);
                case Dat15RelType.Unk7: return new Dat15Unk7(d, br);
                case Dat15RelType.Unk8: return new Dat15Unk8(d, br);
                case Dat15RelType.GroupMap: return new Dat15GroupMap(d, br);
                default:
                    break;
            }

            return d;
        }
        private RelData ReadData16(RelData d, BinaryReader br)
        {
            switch ((Dat16RelType)d.TypeID)
            {
                case Dat16RelType.ConstantCurve: return new Dat16ConstantCurve(d, br);
                case Dat16RelType.LinearCurve: return new Dat16LinearCurve(d, br);
                case Dat16RelType.LinearDbCurve: return new Dat16LinearDbCurve(d, br);
                case Dat16RelType.PiecewiseLinearCurve: return new Dat16PiecewiseLinearCurve(d, br);
                case Dat16RelType.EqualPowerCurve: return new Dat16EqualPowerCurve(d, br);
                case Dat16RelType.ValueTableCurve: return new Dat16ValueTableCurve(d, br);
                case Dat16RelType.ExponentialCurve: return new Dat16ExponentialCurve(d, br);
                case Dat16RelType.DecayingExponentialCurve: return new Dat16DecayingExponentialCurve(d, br);
                case Dat16RelType.DecayingSquaredExponentialCurve: return new Dat16DecayingSquaredExponentialCurve(d, br);
                case Dat16RelType.SineCurve: return new Dat16SineCurve(d, br);
                case Dat16RelType.OneOverXSquaredCurve: return new Dat16OneOverXSquaredCurve(d, br);
                case Dat16RelType.DefaultDistanceAttenuationCurve: return new Dat16DefaultDistanceAttenuationCurve(d, br);
                case Dat16RelType.DistanceAttenuationValueTableCurve: return new Dat16DistanceAttenuationValueTableCurve(d, br);
                default:
                    break;
            }

            return d;
        }
        private RelData ReadData22(RelData d, BinaryReader br)
        {
            switch ((Dat22RelType)d.TypeID)
            {
                case Dat22RelType.Category: return new Dat22Category(d, br);
                default:
                    break;
            }

            return d;
        }
        private RelData ReadData54(RelData d, BinaryReader br)
        {
            switch ((Dat54SoundType)d.TypeID)
            {
                case Dat54SoundType.LoopingSound: return new Dat54LoopingSound(d, br);
                case Dat54SoundType.EnvelopeSound: return new Dat54EnvelopeSound(d, br);
                case Dat54SoundType.TwinLoopSound: return new Dat54TwinLoopSound(d, br);
                case Dat54SoundType.SpeechSound: return new Dat54SpeechSound(d, br);
                case Dat54SoundType.OnStopSound: return new Dat54OnStopSound(d, br);
                case Dat54SoundType.WrapperSound: return new Dat54WrapperSound(d, br);
                case Dat54SoundType.SequentialSound: return new Dat54SequentialSound(d, br);
                case Dat54SoundType.StreamingSound: return new Dat54StreamingSound(d, br);
                case Dat54SoundType.RetriggeredOverlappedSound: return new Dat54RetriggeredOverlappedSound(d, br);
                case Dat54SoundType.CrossfadeSound: return new Dat54CrossfadeSound(d, br);
                case Dat54SoundType.CollapsingStereoSound: return new Dat54CollapsingStereoSound(d, br);
                case Dat54SoundType.SimpleSound: return new Dat54SimpleSound(d, br);
                case Dat54SoundType.MultitrackSound: return new Dat54MultitrackSound(d, br);
                case Dat54SoundType.RandomizedSound: return new Dat54RandomizedSound(d, br);
                case Dat54SoundType.EnvironmentSound: return new Dat54EnvironmentSound(d, br);
                case Dat54SoundType.DynamicEntitySound: return new Dat54DynamicEntitySound(d, br);
                case Dat54SoundType.SequentialOverlapSound: return new Dat54SequentialOverlapSound(d, br);
                case Dat54SoundType.ModularSynthSound: return new Dat54ModularSynthSound(d, br);
                case Dat54SoundType.GranularSound: return new Dat54GranularSound(d, br);
                case Dat54SoundType.DirectionalSound: return new Dat54DirectionalSound(d, br);
                case Dat54SoundType.KineticSound: return new Dat54KineticSound(d, br);
                case Dat54SoundType.SwitchSound: return new Dat54SwitchSound(d, br);
                case Dat54SoundType.VariableCurveSound: return new Dat54VariableCurveSound(d, br);
                case Dat54SoundType.VariablePrintValueSound: return new Dat54VariablePrintValueSound(d, br);
                case Dat54SoundType.VariableBlockSound: return new Dat54VariableBlockSound(d, br);
                case Dat54SoundType.IfSound: return new Dat54IfSound(d, br);
                case Dat54SoundType.MathOperationSound: return new Dat54MathOperationSound(d, br);
                case Dat54SoundType.ParameterTransformSound: return new Dat54ParameterTransformSound(d, br);
                case Dat54SoundType.FluctuatorSound: return new Dat54FluctuatorSound(d, br);
                case Dat54SoundType.AutomationSound: return new Dat54AutomationSound(d, br);
                case Dat54SoundType.ExternalStreamSound: return new Dat54ExternalStreamSound(d, br);
                case Dat54SoundType.SoundSet: return new Dat54SoundSet(d, br);
                case Dat54SoundType.AutomationNoteMapSound: return new Dat54AutomationNoteMapSound(d, br);
                case Dat54SoundType.SoundSetList: return new Dat54SoundSetList(d, br);
                case Dat54SoundType.SoundHashList: return new Dat54SoundHashList(d, br);
                default:
                    return new Dat54Sound(d, br); //shouldn't get here
            }
        }
        private RelData ReadData149(RelData d, BinaryReader br)
        {
            return ReadData151(d, br);//same as 151?
        }
        private RelData ReadData150(RelData d, BinaryReader br)
        {
            return ReadData151(d, br);//same as 151?
        }
        private RelData ReadData151(RelData d, BinaryReader br)
        {
            switch ((Dat151RelType)d.TypeID)
            {
                case Dat151RelType.StaticEmitterList: return new Dat151StaticEmitterList(d, br);
                case Dat151RelType.AmbientZone: return new Dat151AmbientZone(d, br);
                case Dat151RelType.AmbientRule: return new Dat151AmbientRule(d, br);
                case Dat151RelType.AmbientZoneList: return new Dat151AmbientZoneList(d, br);
                case Dat151RelType.Collision: return new Dat151Collision(d, br);
                case Dat151RelType.WeaponAudioItem: return new Dat151WeaponAudioItem(d, br);
                case Dat151RelType.StartTrackAction: return new Dat151StartTrackAction(d, br);
                case Dat151RelType.StopTrackAction: return new Dat151StopTrackAction(d, br);
                case Dat151RelType.Mood: return new Dat151Mood(d, br);
                case Dat151RelType.SetMoodAction: return new Dat151SetMoodAction(d, br);
                case Dat151RelType.PlayerAction: return new Dat151PlayerAction(d, br);
                case Dat151RelType.StartOneShotAction: return new Dat151StartOneShotAction(d, br);
                case Dat151RelType.StopOneShotAction: return new Dat151StopOneShotAction(d, br);
                case Dat151RelType.FadeOutRadioAction: return new Dat151FadeOutRadioAction(d, br);
                case Dat151RelType.FadeInRadioAction: return new Dat151FadeInRadioAction(d, br);
                case Dat151RelType.Mod: return new Dat151Mod(d, br);
                case Dat151RelType.Interior: return new Dat151Interior(d, br);
                case Dat151RelType.InteriorRoom: return new Dat151InteriorRoom(d, br);
                case Dat151RelType.DoorModel: return new Dat151DoorModel(d, br);
                case Dat151RelType.AudioMaterial: return new Dat151AudioMaterial(d, br);
                case Dat151RelType.Door: return new Dat151Door(d, br);
                case Dat151RelType.AnimalFootsteps: return new Dat151AnimalFootsteps(d, br);
                case Dat151RelType.RadioDJSpeechAction: return new Dat151RadioDjSpeechAction(d, br);
                case Dat151RelType.ForceRadioTrackAction: return new Dat151ForceRadioTrackAction(d, br);
                case Dat151RelType.MicrophoneList: return new Dat151MicrophoneList(d, br);
                case Dat151RelType.RadioStationList: return new Dat151RadioStationList(d, br);
                case Dat151RelType.RadioStation: return new Dat151RadioStation(d, br);
                case Dat151RelType.RadioMusic: return new Dat151RadioMusic(d, br);
                case Dat151RelType.RadioTrackList: return new Dat151RadioTrackList(d, br);
                case Dat151RelType.DoorList: return new Dat151DoorList(d, br);
                case Dat151RelType.ShoeList: return new Dat151ShoeList(d, br);
                case Dat151RelType.ClothList: return new Dat151ClothList(d, br);
                case Dat151RelType.VehicleRecordList: return new Dat151VehicleRecordList(d, br);
                case Dat151RelType.WeatherTypeList: return new Dat151WeatherTypeList(d, br);
                case Dat151RelType.ShoreLinePool: return new Dat151ShoreLinePool(d, br);
                case Dat151RelType.ShoreLineLake: return new Dat151ShoreLineLake(d, br);
                case Dat151RelType.ShoreLineRiver: return new Dat151ShoreLineRiver(d, br);
                case Dat151RelType.ShoreLineOcean: return new Dat151ShoreLineOcean(d, br);
                case Dat151RelType.ShoreLineList: return new Dat151ShoreLineList(d, br);
                case Dat151RelType.RadioTrackEvents: return new Dat151RadioTrackEvents(d, br);
                case Dat151RelType.VehicleEngineGranular: return new Dat151VehicleEngineGranular(d, br);
                case Dat151RelType.Vehicle: return new Dat151Vehicle(d, br);
                case Dat151RelType.VehicleEngine: return new Dat151VehicleEngine(d, br);
                case Dat151RelType.VehicleScannerParams: return new Dat151VehicleScannerParams(d, br);
                case Dat151RelType.StaticEmitter: return new Dat151StaticEmitter(d, br);
                case Dat151RelType.Weapon: return new Dat151Weapon(d, br);
                case Dat151RelType.Explosion: return new Dat151Explosion(d, br);
                case Dat151RelType.PedVoiceGroup: return new Dat151PedVoiceGroup(d, br);
                case Dat151RelType.EntityEmitter: return new Dat151EntityEmitter(d, br);
                case Dat151RelType.Boat: return new Dat151Boat(d, br);
                case Dat151RelType.Bicycle: return new Dat151Bicycle(d, br);
                case Dat151RelType.Aeroplane: return new Dat151Aeroplane(d, br);
                case Dat151RelType.Helicopter: return new Dat151Helicopter(d, br);
                case Dat151RelType.VehicleTrailer: return new Dat151VehicleTrailer(d, br);
                case Dat151RelType.Train: return new Dat151Train(d, br);
                case Dat151RelType.AnimalParams: return new Dat151AnimalParams(d, br);
                case Dat151RelType.SpeechParams: return new Dat151SpeechParams(d, br);
                case Dat151RelType.MeleeCombat: return new Dat151MeleeCombat(d, br);
                case Dat151RelType.SpeechContext: return new Dat151SpeechContext(d, br);
                case Dat151RelType.SpeechChoice: return new Dat151SpeechChoice(d, br);
                case Dat151RelType.SpeechChoice2: return new Dat151SpeechChoice2(d, br);
                case Dat151RelType.SpeechContextList: return new Dat151SpeechContextList(d, br);
                case Dat151RelType.Shoe: return new Dat151Shoe(d, br);
                case Dat151RelType.Unk22: return new Dat151Unk22(d, br);
                case Dat151RelType.Unk23: return new Dat151Unk23(d, br);
                case Dat151RelType.Unk27: return new Dat151Unk27(d, br);
                case Dat151RelType.Unk28: return new Dat151Unk28(d, br);
                case Dat151RelType.RaceToPedVoiceGroup: return new Dat151RaceToPedVoiceGroup(d, br);
                case Dat151RelType.PedType: return new Dat151PedType(d, br);
                case Dat151RelType.PoliceScannerReport: return new Dat151PoliceScannerReport(d, br);
                case Dat151RelType.PoliceScannerLocation: return new Dat151PoliceScannerLocation(d, br);
                case Dat151RelType.PoliceScannerLocationList: return new Dat151PoliceScannerLocationList(d, br);
                case Dat151RelType.AmbientStreamList: return new Dat151AmbientStreamList(d, br);
                case Dat151RelType.AmbienceBankMap: return new Dat151AmbienceBankMap(d, br);
                case Dat151RelType.AmbientZoneParams: return new Dat151AmbientZoneParams(d, br);
                case Dat151RelType.InteriorRoomParams: return new Dat151InteriorRoomParams(d, br);
                case Dat151RelType.DoorParams: return new Dat151DoorParams(d, br);
                case Dat151RelType.Climbing: return new Dat151Climbing(d, br);
                case Dat151RelType.WeatherType: return new Dat151WeatherType(d, br);
                case Dat151RelType.StemMix: return new Dat151StemMix(d, br);
                case Dat151RelType.MusicBeat: return new Dat151MusicBeat(d, br);
                case Dat151RelType.MusicBar: return new Dat151MusicBar(d, br);
                case Dat151RelType.DependentAmbience: return new Dat151DependentAmbience(d, br);
                case Dat151RelType.Unk72: return new Dat151Unk72(d, br);
                case Dat151RelType.AnimalSounds: return new Dat151AnimalSounds(d, br);
                case Dat151RelType.VehicleScannerColourList: return new Dat151VehicleScannerColourList(d, br);
                case Dat151RelType.Unk77: return new Dat151Unk77(d, br);
                case Dat151RelType.Microphone: return new Dat151Microphone(d, br);
                case Dat151RelType.VehicleRecord: return new Dat151VehicleRecord(d, br);
                case Dat151RelType.AnimalFootstepsSounds: return new Dat151AnimalFootstepsSounds(d, br);
                case Dat151RelType.Cloth: return new Dat151Cloth(d, br);
                case Dat151RelType.Unk95: return new Dat151Unk95(d, br);
                case Dat151RelType.Unk96: return new Dat151Unk96(d, br);
                case Dat151RelType.Unk99: return new Dat151Unk99(d, br);
                case Dat151RelType.Tunnel: return new Dat151Tunnel(d, br);
                case Dat151RelType.Alarm: return new Dat151Alarm(d, br);
                case Dat151RelType.SlowMoSettings: return new Dat151SlowMoSettings(d, br);
                case Dat151RelType.Scenario: return new Dat151Scenario(d, br);
                case Dat151RelType.AudioOcclusionOverride: return new Dat151AudioOcclusionOverride(d, br);
                case Dat151RelType.ElectricEngine: return new Dat151ElectricEngine(d, br);
                case Dat151RelType.Unk109: return new Dat151Unk109(d, br);
                case Dat151RelType.Unk110: return new Dat151Unk110(d, br);
                case Dat151RelType.AircraftWarningSettings: return new Dat151AircraftWarningSettings(d, br);
                case Dat151RelType.Unk112: return new Dat151Unk112(d, br);
                case Dat151RelType.CopDispatchInteractionSettings: return new Dat151CopDispatchInteractionSettings(d, br);
                case Dat151RelType.Unk115: return new Dat151Unk115(d, br);
                case Dat151RelType.Unk116: return new Dat151Unk116(d, br);
                case Dat151RelType.Unk118: return new Dat151Unk118(d, br);
                case Dat151RelType.Unk119: return new Dat151Unk119(d, br);
                case Dat151RelType.MacsModelsOverrides: return new Dat151MacsModelsOverrides(d, br);
                case Dat151RelType.RadioStationList2: return new Dat151RadioStationList2(d, br);
                default:
                    return new Dat151RelData(d, br); //shouldn't get here
            }
        }


        public RelData CreateRelData(RelDatFileType relType, int dataType)
        {
            RelData d = null;
            switch (relType)
            {
                case RelDatFileType.Dat54DataEntries:
                    switch ((Dat54SoundType)dataType)
                    {
                        case Dat54SoundType.LoopingSound: return new Dat54LoopingSound(this);
                        case Dat54SoundType.EnvelopeSound: return new Dat54EnvelopeSound(this);
                        case Dat54SoundType.TwinLoopSound: return new Dat54TwinLoopSound(this);
                        case Dat54SoundType.SpeechSound: return new Dat54SpeechSound(this);
                        case Dat54SoundType.OnStopSound: return new Dat54OnStopSound(this);
                        case Dat54SoundType.WrapperSound: return new Dat54WrapperSound(this);
                        case Dat54SoundType.SequentialSound: return new Dat54SequentialSound(this);
                        case Dat54SoundType.StreamingSound: return new Dat54StreamingSound(this);
                        case Dat54SoundType.RetriggeredOverlappedSound: return new Dat54RetriggeredOverlappedSound(this);
                        case Dat54SoundType.CrossfadeSound: return new Dat54CrossfadeSound(this);
                        case Dat54SoundType.CollapsingStereoSound: return new Dat54CollapsingStereoSound(this);
                        case Dat54SoundType.SimpleSound: return new Dat54SimpleSound(this);
                        case Dat54SoundType.MultitrackSound: return new Dat54MultitrackSound(this);
                        case Dat54SoundType.RandomizedSound: return new Dat54RandomizedSound(this);
                        case Dat54SoundType.EnvironmentSound: return new Dat54EnvironmentSound(this);
                        case Dat54SoundType.DynamicEntitySound: return new Dat54DynamicEntitySound(this);
                        case Dat54SoundType.SequentialOverlapSound: return new Dat54SequentialOverlapSound(this);
                        case Dat54SoundType.ModularSynthSound: return new Dat54ModularSynthSound(this);
                        case Dat54SoundType.GranularSound: return new Dat54GranularSound(this);
                        case Dat54SoundType.DirectionalSound: return new Dat54DirectionalSound(this);
                        case Dat54SoundType.KineticSound: return new Dat54KineticSound(this);
                        case Dat54SoundType.SwitchSound: return new Dat54SwitchSound(this);
                        case Dat54SoundType.VariableCurveSound: return new Dat54VariableCurveSound(this);
                        case Dat54SoundType.VariablePrintValueSound: return new Dat54VariablePrintValueSound(this);
                        case Dat54SoundType.VariableBlockSound: return new Dat54VariableBlockSound(this);
                        case Dat54SoundType.IfSound: return new Dat54IfSound(this);
                        case Dat54SoundType.MathOperationSound: return new Dat54MathOperationSound(this);
                        case Dat54SoundType.ParameterTransformSound: return new Dat54ParameterTransformSound(this);
                        case Dat54SoundType.FluctuatorSound: return new Dat54FluctuatorSound(this);
                        case Dat54SoundType.AutomationSound: return new Dat54AutomationSound(this);
                        case Dat54SoundType.ExternalStreamSound: return new Dat54ExternalStreamSound(this);
                        case Dat54SoundType.SoundSet: return new Dat54SoundSet(this);
                        case Dat54SoundType.AutomationNoteMapSound: return new Dat54AutomationNoteMapSound(this);
                        case Dat54SoundType.SoundSetList: return new Dat54SoundSetList(this);
                        case Dat54SoundType.SoundHashList: return new Dat54SoundHashList(this);
                        default:
                            return new Dat54Sound(this, (Dat54SoundType)d.TypeID); //shouldn't get here
                    }
                case RelDatFileType.Dat149:
                case RelDatFileType.Dat150:
                case RelDatFileType.Dat151:
                    switch ((Dat151RelType)dataType)
                    {
                        case Dat151RelType.StaticEmitterList: return new Dat151StaticEmitterList(this);
                        case Dat151RelType.AmbientZone: return new Dat151AmbientZone(this);
                        case Dat151RelType.AmbientRule: return new Dat151AmbientRule(this);
                        case Dat151RelType.AmbientZoneList: return new Dat151AmbientZoneList(this);
                        case Dat151RelType.Collision: return new Dat151Collision(this);
                        case Dat151RelType.WeaponAudioItem: return new Dat151WeaponAudioItem(this);
                        case Dat151RelType.StartTrackAction: return new Dat151StartTrackAction(this);
                        case Dat151RelType.StopTrackAction: return new Dat151StopTrackAction(this);
                        case Dat151RelType.Mood: return new Dat151Mood(this);
                        case Dat151RelType.SetMoodAction: return new Dat151SetMoodAction(this);
                        case Dat151RelType.PlayerAction: return new Dat151PlayerAction(this);
                        case Dat151RelType.StartOneShotAction: return new Dat151StartOneShotAction(this);
                        case Dat151RelType.StopOneShotAction: return new Dat151StopOneShotAction(this);
                        case Dat151RelType.FadeOutRadioAction: return new Dat151FadeOutRadioAction(this);
                        case Dat151RelType.FadeInRadioAction: return new Dat151FadeInRadioAction(this);
                        case Dat151RelType.Mod: return new Dat151Mod(this);
                        case Dat151RelType.Interior: return new Dat151Interior(this);
                        case Dat151RelType.InteriorRoom: return new Dat151InteriorRoom(this);
                        case Dat151RelType.DoorModel: return new Dat151DoorModel(this);
                        case Dat151RelType.AudioMaterial: return new Dat151AudioMaterial(this);
                        case Dat151RelType.Door: return new Dat151Door(this);
                        case Dat151RelType.AnimalFootsteps: return new Dat151AnimalFootsteps(this);
                        case Dat151RelType.RadioDJSpeechAction: return new Dat151RadioDjSpeechAction(this);
                        case Dat151RelType.ForceRadioTrackAction: return new Dat151ForceRadioTrackAction(this);
                        case Dat151RelType.MicrophoneList: return new Dat151MicrophoneList(this);
                        case Dat151RelType.RadioStationList: return new Dat151RadioStationList(this);
                        case Dat151RelType.RadioStation: return new Dat151RadioStation(this);
                        case Dat151RelType.RadioMusic: return new Dat151RadioMusic(this);
                        case Dat151RelType.RadioTrackList: return new Dat151RadioTrackList(this);
                        case Dat151RelType.DoorList: return new Dat151DoorList(this);
                        case Dat151RelType.ShoeList: return new Dat151ShoeList(this);
                        case Dat151RelType.ClothList: return new Dat151ClothList(this);
                        case Dat151RelType.VehicleRecordList: return new Dat151VehicleRecordList(this);
                        case Dat151RelType.WeatherTypeList: return new Dat151WeatherTypeList(this);
                        case Dat151RelType.ShoreLinePool: return new Dat151ShoreLinePool(this);
                        case Dat151RelType.ShoreLineLake: return new Dat151ShoreLineLake(this);
                        case Dat151RelType.ShoreLineRiver: return new Dat151ShoreLineRiver(this);
                        case Dat151RelType.ShoreLineOcean: return new Dat151ShoreLineOcean(this);
                        case Dat151RelType.ShoreLineList: return new Dat151ShoreLineList(this);
                        case Dat151RelType.RadioTrackEvents: return new Dat151RadioTrackEvents(this);
                        case Dat151RelType.VehicleEngineGranular: return new Dat151VehicleEngineGranular(this);
                        case Dat151RelType.Vehicle: return new Dat151Vehicle(this);
                        case Dat151RelType.VehicleEngine: return new Dat151VehicleEngine(this);
                        case Dat151RelType.VehicleScannerParams: return new Dat151VehicleScannerParams(this);
                        case Dat151RelType.StaticEmitter: return new Dat151StaticEmitter(this);
                        case Dat151RelType.Weapon: return new Dat151Weapon(this);
                        case Dat151RelType.Explosion: return new Dat151Explosion(this);
                        case Dat151RelType.PedVoiceGroup: return new Dat151PedVoiceGroup(this);
                        case Dat151RelType.EntityEmitter: return new Dat151EntityEmitter(this);
                        case Dat151RelType.Boat: return new Dat151Boat(this);
                        case Dat151RelType.Bicycle: return new Dat151Bicycle(this);
                        case Dat151RelType.Aeroplane: return new Dat151Aeroplane(this);
                        case Dat151RelType.Helicopter: return new Dat151Helicopter(this);
                        case Dat151RelType.VehicleTrailer: return new Dat151VehicleTrailer(this);
                        case Dat151RelType.Train: return new Dat151Train(this);
                        case Dat151RelType.AnimalParams: return new Dat151AnimalParams(this);
                        case Dat151RelType.SpeechParams: return new Dat151SpeechParams(this);
                        case Dat151RelType.MeleeCombat: return new Dat151MeleeCombat(this);
                        case Dat151RelType.SpeechContext: return new Dat151SpeechContext(this);
                        case Dat151RelType.SpeechChoice: return new Dat151SpeechChoice(this);
                        case Dat151RelType.SpeechChoice2: return new Dat151SpeechChoice2(this);
                        case Dat151RelType.SpeechContextList: return new Dat151SpeechContextList(this);
                        case Dat151RelType.Shoe: return new Dat151Shoe(this);
                        case Dat151RelType.Unk22: return new Dat151Unk22(this);
                        case Dat151RelType.Unk23: return new Dat151Unk23(this);
                        case Dat151RelType.Unk27: return new Dat151Unk27(this);
                        case Dat151RelType.Unk28: return new Dat151Unk28(this);
                        case Dat151RelType.RaceToPedVoiceGroup: return new Dat151RaceToPedVoiceGroup(this);
                        case Dat151RelType.PedType: return new Dat151PedType(this);
                        case Dat151RelType.PoliceScannerReport: return new Dat151PoliceScannerReport(this);
                        case Dat151RelType.PoliceScannerLocation: return new Dat151PoliceScannerLocation(this);
                        case Dat151RelType.PoliceScannerLocationList: return new Dat151PoliceScannerLocationList(this);
                        case Dat151RelType.AmbientStreamList: return new Dat151AmbientStreamList(this);
                        case Dat151RelType.AmbienceBankMap: return new Dat151AmbienceBankMap(this);
                        case Dat151RelType.AmbientZoneParams: return new Dat151AmbientZoneParams(this);
                        case Dat151RelType.InteriorRoomParams: return new Dat151InteriorRoomParams(this);
                        case Dat151RelType.DoorParams: return new Dat151DoorParams(this);
                        case Dat151RelType.Climbing: return new Dat151Climbing(this);
                        case Dat151RelType.WeatherType: return new Dat151WeatherType(this);
                        case Dat151RelType.StemMix: return new Dat151StemMix(this);
                        case Dat151RelType.MusicBeat: return new Dat151MusicBeat(this);
                        case Dat151RelType.MusicBar: return new Dat151MusicBar(this);
                        case Dat151RelType.DependentAmbience: return new Dat151DependentAmbience(this);
                        case Dat151RelType.Unk72: return new Dat151Unk72(this);
                        case Dat151RelType.AnimalSounds: return new Dat151AnimalSounds(this);
                        case Dat151RelType.VehicleScannerColourList: return new Dat151VehicleScannerColourList(this);
                        case Dat151RelType.Unk77: return new Dat151Unk77(this);
                        case Dat151RelType.Microphone: return new Dat151Microphone(this);
                        case Dat151RelType.VehicleRecord: return new Dat151VehicleRecord(this);
                        case Dat151RelType.AnimalFootstepsSounds: return new Dat151AnimalFootstepsSounds(this);
                        case Dat151RelType.Cloth: return new Dat151Cloth(this);
                        case Dat151RelType.Unk95: return new Dat151Unk95(this);
                        case Dat151RelType.Unk96: return new Dat151Unk96(this);
                        case Dat151RelType.Unk99: return new Dat151Unk99(this);
                        case Dat151RelType.Tunnel: return new Dat151Tunnel(this);
                        case Dat151RelType.Alarm: return new Dat151Alarm(this);
                        case Dat151RelType.SlowMoSettings: return new Dat151SlowMoSettings(this);
                        case Dat151RelType.Scenario: return new Dat151Scenario(this);
                        case Dat151RelType.AudioOcclusionOverride: return new Dat151AudioOcclusionOverride(this);
                        case Dat151RelType.ElectricEngine: return new Dat151ElectricEngine(this);
                        case Dat151RelType.Unk109: return new Dat151Unk109(this);
                        case Dat151RelType.Unk110: return new Dat151Unk110(this);
                        case Dat151RelType.AircraftWarningSettings: return new Dat151AircraftWarningSettings(this);
                        case Dat151RelType.Unk112: return new Dat151Unk112(this);
                        case Dat151RelType.CopDispatchInteractionSettings: return new Dat151CopDispatchInteractionSettings(this);
                        case Dat151RelType.Unk115: return new Dat151Unk115(this);
                        case Dat151RelType.Unk116: return new Dat151Unk116(this);
                        case Dat151RelType.Unk118: return new Dat151Unk118(this);
                        case Dat151RelType.Unk119: return new Dat151Unk119(this);
                        case Dat151RelType.MacsModelsOverrides: return new Dat151MacsModelsOverrides(this);
                        case Dat151RelType.RadioStationList2: return new Dat151RadioStationList2(this);
                        default:
                            return new Dat151RelData(this, (Dat151RelType)dataType); //shouldn't get here
                    }
                case RelDatFileType.Dat4:
                    if (IsAudioConfig)
                    {
                        switch((Dat4ConfigType)dataType)
                        {
                            case Dat4ConfigType.Int: return new Dat4ConfigInt(this);
                            case Dat4ConfigType.Int2: return new Dat4ConfigInt2(this);
                            case Dat4ConfigType.Float: return new Dat4ConfigFloat(this);
                            case Dat4ConfigType.String: return new Dat4ConfigString(this);
                            case Dat4ConfigType.Orientation: return new Dat4ConfigOrientation(this);
                            case Dat4ConfigType.VariableList: return new Dat4ConfigVariableList(this);
                            case Dat4ConfigType.WaveSlot: return new Dat4ConfigWaveSlot(this);
                            case Dat4ConfigType.WaveSlotsList: return new Dat4ConfigWaveSlotsList(this);
                            case Dat4ConfigType.UnkER: return new Dat4ConfigUnkER(this);
                            default:
                                d = new RelData(this);
                                d.TypeID = (byte)dataType;
                                return d;
                        }
                    }
                    else
                    {
                        d = new Dat4SpeechData(this);
                        d.TypeID = (byte)dataType;
                        (d as Dat4SpeechData).Type = (Dat4SpeechType)dataType;
                        return d;
                    }
                case RelDatFileType.Dat10ModularSynth:
                    switch ((Dat10RelType)dataType)
                    {
                        case Dat10RelType.SynthPreset: return new Dat10SynthPreset(this);
                        case Dat10RelType.Synth: return new Dat10Synth(this);
                        default:
                            return new Dat10RelData(this);//shouldn't get here
                    }
                case RelDatFileType.Dat15DynamicMixer:
                    switch ((Dat15RelType)dataType)
                    {
                        case Dat15RelType.Patch: return new Dat15Patch(this);
                        case Dat15RelType.Unk1: return new Dat15Unk1(this);
                        case Dat15RelType.Scene: return new Dat15Scene(this);
                        case Dat15RelType.Group: return new Dat15Group(this);
                        case Dat15RelType.GroupList: return new Dat15GroupList(this);
                        case Dat15RelType.Unk5: return new Dat15Unk5(this);
                        case Dat15RelType.Unk6: return new Dat15Unk6(this);
                        case Dat15RelType.Unk7: return new Dat15Unk7(this);
                        case Dat15RelType.Unk8: return new Dat15Unk8(this);
                        case Dat15RelType.GroupMap: return new Dat15GroupMap(this);
                        default:
                            return new Dat15RelData(this);//shouldn't get here
                    }
                case RelDatFileType.Dat16Curves:
                    switch ((Dat16RelType)dataType)
                    {
                        case Dat16RelType.ConstantCurve: return new Dat16ConstantCurve(this);
                        case Dat16RelType.LinearCurve: return new Dat16LinearCurve(this);
                        case Dat16RelType.LinearDbCurve: return new Dat16LinearDbCurve(this);
                        case Dat16RelType.PiecewiseLinearCurve: return new Dat16PiecewiseLinearCurve(this);
                        case Dat16RelType.EqualPowerCurve: return new Dat16EqualPowerCurve(this);
                        case Dat16RelType.ValueTableCurve: return new Dat16ValueTableCurve(this);
                        case Dat16RelType.ExponentialCurve: return new Dat16ExponentialCurve(this);
                        case Dat16RelType.DecayingExponentialCurve: return new Dat16DecayingExponentialCurve(this);
                        case Dat16RelType.DecayingSquaredExponentialCurve: return new Dat16DecayingSquaredExponentialCurve(this);
                        case Dat16RelType.SineCurve: return new Dat16SineCurve(this);
                        case Dat16RelType.OneOverXSquaredCurve: return new Dat16OneOverXSquaredCurve(this);
                        case Dat16RelType.DefaultDistanceAttenuationCurve: return new Dat16DefaultDistanceAttenuationCurve(this);
                        case Dat16RelType.DistanceAttenuationValueTableCurve: return new Dat16DistanceAttenuationValueTableCurve(this);
                        default:
                            return new Dat16RelData(this);//shouldn't get here
                    }
                case RelDatFileType.Dat22Categories:
                    switch ((Dat22RelType)dataType)
                    {
                        case Dat22RelType.Category: return new Dat22Category(this);
                        default:
                            return new Dat22RelData(this);//shouldn't get here
                    }
                default:
                    d = new RelData(this);
                    d.TypeID = (byte)dataType;
                    return d;
            }
        }



        private void BuildNameTable()
        {
            //TODO!
            //need to do this before building the data block since nametable offsets are in there!






            if (NameTable != null)
            {
                NameTableCount = (uint)NameTable.Length;
                uint ntlength = 4 + (4 * NameTableCount);
                foreach (var name in NameTable)
                {
                    ntlength += (uint)name.Length + 1;
                }
                if ((NameTableLength != ntlength)&&(NameTableLength!=0))
                { }
                NameTableLength = ntlength;
            }
            else
            {
                if ((NameTableLength != 4)&& (NameTableLength != 0))
                { }
                NameTableCount = 0;
                NameTableLength = 4;
            }


        }
        private void BuildDataBlock()
        {
            if (RelDatas == null) return;
            if (RelDatasSorted == null) return;



            MemoryStream ms = new MemoryStream();
            BinaryWriter bw = new BinaryWriter(ms);

            bw.Write(DataUnkVal);


            RelData lastrd = null;//debug

            for (int i = 0; i < RelDatasSorted.Length; i++)
            {

                var rd = RelDatasSorted[i];

                switch (RelType)
                {
                    case RelDatFileType.Dat10ModularSynth:
                        while ((ms.Position & 3) != 0) bw.Write((byte)0); //align these to nearest 4 bytes
                        break;
                    case RelDatFileType.Dat15DynamicMixer:
                        switch (rd.TypeID)
                        {
                            case 0:
                            case 6:
                            case 5:
                            case 7:
                            case 8:
                                while ((ms.Position & 3) != 0) bw.Write((byte)0); //align these to nearest 4 bytes
                                break;
                            default:
                                break;
                        }
                        break;
                    case RelDatFileType.Dat149:
                    case RelDatFileType.Dat150:
                    case RelDatFileType.Dat151:
                        switch ((Dat151RelType)rd.TypeID)//must be a better way of doing this!
                        {
                            case Dat151RelType.AmbientRule:
                            case Dat151RelType.AmbientZone:
                            case Dat151RelType.Alarm:
                            case Dat151RelType.PoliceScannerLocation:
                                while ((ms.Position & 0xF) != 0) bw.Write((byte)0); //align to nearest 16 bytes
                                break;
                            case Dat151RelType.Mood:
                            case Dat151RelType.MusicBar:
                            case Dat151RelType.RaceToPedVoiceGroup:
                            case Dat151RelType.SpeechParams:
                            case Dat151RelType.SpeechContext:
                            case Dat151RelType.AmbienceBankMap:
                            case Dat151RelType.VehicleTrailer:
                            case Dat151RelType.StaticEmitterList:
                            case Dat151RelType.Weapon:
                            case Dat151RelType.Vehicle:
                            case Dat151RelType.StopTrackAction:
                                while ((ms.Position & 3) != 0) bw.Write((byte)0); //align these to nearest 4 bytes
                                break;
                        }
                        break;
                    case RelDatFileType.Dat4:
                        if (IsAudioConfig)
                        {
                            switch ((Dat4ConfigType)rd.TypeID)
                            {
                                case Dat4ConfigType.Orientation:
                                    while ((ms.Position & 0xF) != 0) bw.Write((byte)0); //align to nearest 16 bytes
                                    break;
                            }
                        }
                        break;
                }


                var pos = ms.Position;
                if ((ms.Position != rd.DataOffset) && (rd.DataOffset != 0))
                { }
                rd.DataOffset = (uint)ms.Position;
                rd.Write(bw);
                var lengthwritten = ms.Position - pos;
                if ((lengthwritten != rd.DataLength) && (rd.DataLength != 0))
                { }
                rd.DataLength = (uint)lengthwritten;

                lastrd = rd;
            }

            var buf = new byte[ms.Length];
            ms.Position = 0;
            ms.Read(buf, 0, buf.Length);

            if ((DataBlock!=null)&&(DataBlock.Length != buf.Length))
            { }

            DataBlock = buf;

            DataLength = (uint)(DataBlock?.Length ?? 0);
        }
        private void BuildIndex()
        {
            if (RelDatas == null) return;
            if (RelDatasSorted == null) return;



            //for the correct index ordering, needs to be in order of hashes, but with bits rotated right by 8 (why!?)
            var sorted = RelDatasSorted.ToList();
            switch (RelType)
            {
                case RelDatFileType.Dat15DynamicMixer:
                case RelDatFileType.Dat149:
                case RelDatFileType.Dat150:
                case RelDatFileType.Dat151:
                case RelDatFileType.Dat10ModularSynth:
                case RelDatFileType.Dat22Categories:
                case RelDatFileType.Dat16Curves:
                case RelDatFileType.Dat54DataEntries:
                    sorted.Sort((a, b) => 
                    {
                        var ah = (uint)a.NameHash;
                        var bh = (uint)b.NameHash;
                        var av = (ah >> 8) | (ah << 24);
                        var bv = (bh >> 8) | (bh << 24);
                        return av.CompareTo(bv);
                    });
                    break;
                default:
                    if (!IsAudioConfig)//don't sort audioconfig (only sort speech dat4's)
                    {
                        sorted.Sort((a, b) => { return ((uint)a.NameHash).CompareTo((uint)b.NameHash); });
                    }
                    break;
            }
            RelDatas = sorted.ToArray();


            if (IsAudioConfig)
            {
                var strs = new RelIndexString[RelDatas.Length];
                for (int i = 0; i < RelDatas.Length; i++)
                {
                    var rd = RelDatas[i];
                    strs[i] = new RelIndexString() { Name = rd.Name, Offset = rd.DataOffset, Length = rd.DataLength };
                }
                IndexStrings = strs;
                IndexCount = (uint)(IndexStrings?.Length ?? 0);
            }
            else
            {

                var hashes = new RelIndexHash[RelDatas.Length];
                for (int i = 0; i < RelDatas.Length; i++)
                {
                    var rd = RelDatas[i];
                    hashes[i] = new RelIndexHash() { Name = rd.NameHash, Offset = rd.DataOffset, Length = rd.DataLength };
                }
                //if (hashes.Length != IndexHashes.Length)
                //{ }

                IndexHashes = hashes;
                IndexCount = (uint)(IndexHashes?.Length ?? 0);
            }
        }
        private void BuildHashTable()
        {
            if (RelDatasSorted == null) return;

            var htoffsets = new List<uint>();
            foreach (var rd in RelDatasSorted)
            {
                var offsets = rd.GetHashTableOffsets();
                if (offsets == null) continue;
                var rdoffset = rd.DataOffset + 8;
                var rs = rd as RelSound;
                var ss = rd as Dat4SpeechData;
                if (rs?.Header != null)
                {
                    rdoffset += 1 + rs.Header.CalcHeaderLength();
                }
                else if (ss == null)//don't add 4 for speech!
                {
                    rdoffset += 4; //typeid + nt offset
                }
                for (int i = 0; i < offsets.Length; i++)
                {
                    htoffsets.Add(rdoffset + offsets[i]);

                    int idx = htoffsets.Count - 1;
                    if ((HashTableOffsets != null) && (idx < HashTableOffsets.Length))
                    {
                        if (htoffsets[idx] != HashTableOffsets[idx])
                        { }
                    }
                }
            }
            if (htoffsets.Count > 0)
            {
                if (HashTableOffsets != null)
                {
                    if (HashTableOffsets.Length != htoffsets.Count)
                    { }
                    else
                    {
                        for (int i = 0; i < htoffsets.Count; i++)
                        {
                            if (htoffsets[i] != HashTableOffsets[i])
                            { }
                        }
                    }
                }
                HashTableOffsets = htoffsets.ToArray();
            }
            else
            {
                HashTableOffsets = null;
            }

            HashTableCount = (uint)(HashTableOffsets?.Length ?? 0);
        }
        private void BuildPackTable()
        {

            var ptoffsets = new List<uint>();
            foreach (var rd in RelDatasSorted)
            {
                var offsets = rd.GetPackTableOffsets();
                if (offsets == null) continue;
                var rdoffset = rd.DataOffset + 8;
                var rs = rd as RelSound;
                var ss = rd as Dat4SpeechData;
                if (rs?.Header != null)
                {
                    rdoffset += 1 + rs.Header.CalcHeaderLength();
                }
                else if (ss == null)//don't add 4 for speech!
                {
                    rdoffset += 4; //typeid + nt offset
                }
                for (int i = 0; i < offsets.Length; i++)
                {
                    ptoffsets.Add(rdoffset + offsets[i]);
                }
            }
            if (ptoffsets.Count > 0)
            {
                if (PackTableOffsets != null)
                {
                    if (PackTableOffsets.Length != ptoffsets.Count)
                    { }
                    else
                    {
                        for (int i = 0; i < ptoffsets.Count; i++)
                        {
                            if (ptoffsets[i] != PackTableOffsets[i])
                            { }
                        }
                    }
                }
                PackTableOffsets = ptoffsets.ToArray();
            }
            else
            {
                PackTableOffsets = null;
            }

            PackTableCount = (uint)(PackTableOffsets?.Length ?? 0);
        }



        private void BuildHashMaps()
        {
            //for discovering "HashTable" offsets

            var relType = RelType;
            switch (RelType)
            {
                case RelDatFileType.Dat149:
                case RelDatFileType.Dat150://treat these same as 151
                case RelDatFileType.Dat151:
                    relType = RelDatFileType.Dat151;
                    break;
                default:
                    break;
            }

            if (relType != RelDatFileType.Dat4)
            { return; }


            if (HashTableOffsets != null)
            {
                foreach (var htoffset in HashTableOffsets)
                {
                    var dboffset = htoffset - 8;
                    for (int i = 0; i < RelDatasSorted.Length; i++)
                    {
                        var rd = RelDatasSorted[i];

                        if ((dboffset >= rd.DataOffset) && (dboffset < rd.DataOffset + rd.DataLength))
                        {
                            var rdoffset = rd.DataOffset;
                            var rs = rd as RelSound;
                            if (rs != null)
                            {
                                rdoffset += 1 + rs.Header.HeaderLength;
                            }
                            var key = new HashesMapKey()
                            {
                                FileType = relType,
                                ItemType = rd.TypeID,
                                IsContainer = false
                            };
                            var val = new HashesMapValue()
                            {
                                Item = rd,
                                Hash = BitConverter.ToUInt32(DataBlock, (int)dboffset),
                                Offset = dboffset - rdoffset,
                                Count = 1
                            };
                            AddHashesMapItem(ref key, val);
                            break;
                        }
                    }
                }
            }
            if (PackTableOffsets != null)
            {
                foreach (var wcoffset in PackTableOffsets)
                {
                    var dboffset = wcoffset - 8;
                    for (int i = 0; i < RelDatasSorted.Length; i++)
                    {
                        var rd = RelDatasSorted[i];
                        if ((dboffset >= rd.DataOffset) && (dboffset < rd.DataOffset + rd.DataLength))
                        {
                            var rdoffset = rd.DataOffset;
                            var rs = rd as RelSound;
                            if (rs != null)
                            {
                                rdoffset += 1 + rs.Header.HeaderLength;
                            }
                            var key = new HashesMapKey()
                            {
                                FileType = relType,
                                ItemType = rd.TypeID,
                                IsContainer = true
                            };
                            var val = new HashesMapValue()
                            {
                                Item = rd,
                                Hash = BitConverter.ToUInt32(DataBlock, (int)dboffset),
                                Offset = dboffset - rdoffset,
                                Count = 1
                            };
                            AddHashesMapItem(ref key, val);
                            break;
                        }
                    }
                }
            }


        }
        public struct HashesMapKey
        {
            public RelDatFileType FileType { get; set; }
            public uint ItemType { get; set; }
            public bool IsContainer { get; set; }

            public override string ToString()
            {
                var cstr = IsContainer ? "Container: " : "";
                var fcstr = cstr + FileType.ToString() + ": ";
                switch (FileType)
                {
                    case RelDatFileType.Dat54DataEntries:
                        return fcstr + ((Dat54SoundType)ItemType).ToString();
                    case RelDatFileType.Dat149:
                    case RelDatFileType.Dat150:
                    case RelDatFileType.Dat151:
                        return fcstr + ((Dat151RelType)ItemType).ToString();
                }

                return fcstr + ItemType.ToString();
            }
        }
        public class HashesMapValue
        {
            public RelData Item { get; set; }
            public MetaHash Hash { get; set; }
            public uint Offset { get; set; }
            public uint Count { get; set; }

            public override string ToString()
            {
                return Offset.ToString() + ": " + Count.ToString();
            }
        }
        public static Dictionary<HashesMapKey, List<HashesMapValue>> HashesMap { get; set; } = new Dictionary<HashesMapKey, List<HashesMapValue>>();
        private static void AddHashesMapItem(ref HashesMapKey key, HashesMapValue val)
        {
            List<HashesMapValue> values = null;
            if (!HashesMap.TryGetValue(key, out values))
            {
                values = new List<HashesMapValue>();
                HashesMap[key] = values;
            }
            if (values != null)
            {
                foreach (var xval in values)
                {
                    if (xval.Offset == val.Offset)
                    {
                        xval.Count++;
                        return;//same key, same offset, it's a match...
                    }
                }
                values.Add(val);
            }
            else
            { }
        }




        public byte[] Save()
        {
            
            BuildNameTable();
            BuildDataBlock();
            BuildIndex();
            BuildHashTable();
            BuildPackTable();


            if (DataBlock == null) return null;



            //write the file data.

            MemoryStream ms = new MemoryStream();
            BinaryWriter bw = new BinaryWriter(ms);


            bw.Write((uint)RelType);
            bw.Write(DataLength);
            bw.Write(DataBlock);

            bw.Write(NameTableLength);
            bw.Write(NameTableCount);
            if (NameTableCount > 0)
            {
                uint offset = 0;
                foreach (var name in NameTable)
                {
                    bw.Write(offset);
                    offset += (uint)name.Length + 1;
                }
                foreach (var name in NameTable)
                {
                    foreach (var c in name)
                    {
                        bw.Write(c);
                    }
                    bw.Write((byte)0);
                }

            }

            bw.Write(IndexCount);
            if (IndexCount > 0)
            {
                if (IsAudioConfig)//audioconfig.dat4.rel
                {
                    bw.Write(IndexStringFlags); //should be 2524..? could be a length?
                    for (uint i = 0; i < IndexCount; i++)
                    {
                        var ristr = IndexStrings[i];
                        var name = ristr.Name;
                        bw.Write((byte)name.Length);
                        for (int j = 0; j < name.Length; j++)
                        {
                            bw.Write((byte)name[j]);
                        }
                        bw.Write(ristr.Offset);
                        bw.Write(ristr.Length);
                    }
                }
                else //for all other .rel files...
                {
                    for (uint i = 0; i < IndexCount; i++)
                    {
                        var rihash = IndexHashes[i];
                        bw.Write(rihash.Name);
                        bw.Write(rihash.Offset);
                        bw.Write(rihash.Length);
                    }
                }
            }

            bw.Write(HashTableCount);
            if (HashTableCount != 0)
            {
                for (uint i = 0; i < HashTableCount; i++)
                {
                    bw.Write(HashTableOffsets[i]);
                }
            }

            bw.Write(PackTableCount);
            if (PackTableCount != 0)
            {
                for (uint i = 0; i < PackTableCount; i++)
                {
                    bw.Write(PackTableOffsets[i]);
                }
            }


            var buf = new byte[ms.Length];
            ms.Position = 0;
            ms.Read(buf, 0, buf.Length);
            return buf;

        }







        public void AddRelData(RelData d)
        {
            var newRelDatas = new List<RelData>();
            var newRelDatasSorted = new List<RelData>();

            if (RelDatas != null) newRelDatas.AddRange(RelDatas);
            if (RelDatasSorted != null) newRelDatasSorted.AddRange(RelDatasSorted);

            newRelDatas.Add(d);
            newRelDatasSorted.Add(d);

            RelDatas = newRelDatas.ToArray();
            RelDatasSorted = newRelDatasSorted.ToArray();
            //RelDataDict[d.NameHash] = d;
        }
        public bool RemoveRelData(RelData d)
        {
            var newRelDatas = new List<RelData>();
            var newRelDatasSorted = new List<RelData>();

            if (RelDatas != null)
            {
                foreach (var relData in RelDatas)
                {
                    if (relData != d)
                    {
                        newRelDatas.Add(relData);
                    }
                }
            }
            if (RelDatasSorted != null)
            {
                foreach (var relData in RelDatasSorted)
                {
                    if (relData != d)
                    {
                        newRelDatasSorted.Add(relData);
                    }
                }
            }

            if (newRelDatas.Count < RelDatas.Length)
            {
                RelDatas = newRelDatas.ToArray();
                RelDatasSorted = newRelDatasSorted.ToArray();
                RelDataDict.Remove(d.NameHash);
                return true;
            }

            return false;
        }



        public override string ToString()
        {
            return Name;
        }
    }

    [TC(typeof(EXP))] public struct RelIndexHash
    {
        public MetaHash Name { get; set; }
        public uint Offset { get; set; }
        public uint Length { get; set; }

        public override string ToString()
        {
            return Name.ToString() + ", " + Offset.ToString() + ", " + Length.ToString();
        }
    }


    [TC(typeof(EXP))] public struct RelIndexString
    {
        public string Name { get; set; }
        public uint Offset { get; set; }
        public uint Length { get; set; }

        public override string ToString()
        {
            return Name + ", " + Offset.ToString() + ", " + Length.ToString();
        }
    }


    [TC(typeof(EXP))] public class RelData
    {
        public MetaHash NameHash { get; set; }
        public string Name { get; set; }
        public uint DataOffset { get; set; }
        public uint DataLength { get; set; }
        public byte[] Data { get; set; }
        public byte TypeID { get; set; }

        public RelFile Rel { get; set; }

        public RelData(RelFile rel) { Rel = rel; }
        public RelData(RelData d)
        {
            NameHash = d.NameHash;
            Name = d.Name;
            DataOffset = d.DataOffset;
            DataLength = d.DataLength;
            Data = d.Data;
            TypeID = d.TypeID;
            Rel = d.Rel;
        }

        public void ReadType(BinaryReader br)
        {
            TypeID = br.ReadByte();
        }

        public virtual uint[] GetHashTableOffsets()
        {
            return null;
        }
        public virtual uint[] GetPackTableOffsets()
        {
            return null;
        }

        public virtual MetaHash[] GetSpeechHashes()
        {
            return null;
        }
        public virtual MetaHash[] GetSynthHashes()
        {
            return null;
        }
        public virtual MetaHash[] GetMixerHashes()
        {
            return null;
        }
        public virtual MetaHash[] GetCurveHashes()
        {
            return null;
        }
        public virtual MetaHash[] GetCategoryHashes()
        {
            return null;
        }
        public virtual MetaHash[] GetSoundHashes()
        {
            return null;
        }
        public virtual MetaHash[] GetGameHashes()
        {
            return null;
        }


        public virtual void Write(BinaryWriter bw)
        {
            bw.Write(Data); //fallback for default byte array data writing...
        }

        public virtual void WriteXml(StringBuilder sb, int indent)
        {
            //default fallback to write raw data to XML...

            RelXml.WriteRawArray(sb, Data, indent, "RawData", "", RelXml.FormatHexByte, 16);

        }

        public virtual void ReadXml(XmlNode node)
        {
            var rawnode = node.SelectSingleNode("RawData");
            if (rawnode != null)
            {
                Data = Xml.GetRawByteArray(rawnode);
                DataLength = (uint)Data.Length;
            }
        }


        public string GetNameString()
        {
            return (string.IsNullOrEmpty(Name)) ? NameHash.ToString() : Name;
        }
        public string GetBaseString()
        {
            return DataOffset.ToString() + ", " + DataLength.ToString() + ": " + GetNameString();
        }
        public override string ToString()
        {
            return GetBaseString() + ": " + TypeID.ToString();
        }

        public static bool Bit(uint f, int b)
        {
            return ((f & (1u << b)) != 0); //just for handyness... maybe move this?
        }
        public static bool BadF(float f)
        {
            return ((f < -15000) || (f > 15000));
        }
    }




    #region dat54



    [TC(typeof(EXP))] public class RelSoundHeader
    {
        public FlagsUint Flags { get; set; }

        public FlagsUint Flags2 { get; set; }
        public ushort Unk01 { get; set; }
        public ushort Volume { get; set; }
        public ushort VolumeVariance { get; set; } //0xD-0xF
        public ushort Pitch { get; set; } //0xF-0x11
        public ushort PitchVariance { get; set; } //0x11-0x13
        public ushort Pan { get; set; } //0x13-0x15
        public ushort PanVariance { get; set; } //0x15-0x17
        public ushort PreDelay { get; set; } //0x17-0x19
        public ushort PreDelayVariance { get; set; } //0x19-0x1B
        public int StartOffset { get; set; } //0x1B-0x1F
        public int StartOffsetVariance { get; set; } //0x1F-0x23
        public ushort AttackTime { get; set; } //0x23-0x25
        public ushort ReleaseTime { get; set; } //0x25-0x27
        public ushort DopplerFactor { get; set; } //0x27-0x29
        public MetaHash Category { get; set; } //0x29-0x2D
        public ushort LPFCutoff { get; set; } //0x2D-0x2F
        public ushort LPFCutoffVariance { get; set; } //0x2F-0x31
        public ushort HPFCutoff { get; set; } //0x31-0x33
        public ushort HPFCutoffVariance { get; set; } //0x33-0x35
        public MetaHash VolumeCurve { get; set; } //0x35-0x39
        public ushort VolumeCurveScale { get; set; } //0x39-0x3B
        public byte VolumeCurvePlateau { get; set; } //0x3B-0x3C
        public byte Timer { get; set; } //0x3C-0x3D
        public byte Unk21 { get; set; } //0x3D-0x3E
        public MetaHash PreDelayVariable { get; set; } //0x3E-0x42
        public MetaHash StartOffsetVariable { get; set; } //0x42-0x46
        public ushort Unk22 { get; set; } //0x46-0x48
        public ushort Unk23 { get; set; } //0x48-0x4A
        public ushort Unk24 { get; set; } //0x4A-0x4C
        public ushort Unk25 { get; set; } //0x4A-0x4C
        public ushort Unk26 { get; set; } //0x4A-0x4C

        public uint HeaderLength { get; set; } = 0;


        public RelSoundHeader(XmlNode node)
        {
            ReadXml(node);
            HeaderLength = CalcHeaderLength();
        }
        public RelSoundHeader(BinaryReader br)
        {
            var pos = br.BaseStream.Position;

            Flags = br.ReadUInt32();

            //if (Flags.Value != 0xAAAAAAAA)
            if ((Flags & 0xFF) != 0xAA)
            {
                if (Bit(0)) Flags2 = br.ReadUInt32();
                if (Bit(1)) Unk01 = br.ReadUInt16();
                if (Bit(2)) Volume = br.ReadUInt16();
                if (Bit(3)) VolumeVariance = br.ReadUInt16();
                if (Bit(4)) Pitch = br.ReadUInt16();
                if (Bit(5)) PitchVariance = br.ReadUInt16();
                if (Bit(6)) Pan = br.ReadUInt16();
                if (Bit(7)) PanVariance = br.ReadUInt16();
            }
            if ((Flags & 0xFF00) != 0xAA00)
            {
                if (Bit(8)) PreDelay = br.ReadUInt16();
                if (Bit(9)) PreDelayVariance = br.ReadUInt16();
                if (Bit(10)) StartOffset = br.ReadInt32();
                if (Bit(11)) StartOffsetVariance = br.ReadInt32();
                if (Bit(12)) AttackTime = br.ReadUInt16();
                if (Bit(13)) ReleaseTime = br.ReadUInt16();
                if (Bit(14)) DopplerFactor = br.ReadUInt16();
                if (Bit(15)) Category = br.ReadUInt32();
            }
            if ((Flags & 0xFF0000) != 0xAA0000)
            {
                if (Bit(16)) LPFCutoff = br.ReadUInt16();
                if (Bit(17)) LPFCutoffVariance = br.ReadUInt16();
                if (Bit(18)) HPFCutoff = br.ReadUInt16();
                if (Bit(19)) HPFCutoffVariance = br.ReadUInt16();
                if (Bit(20)) VolumeCurve = br.ReadUInt32();
                if (Bit(21)) VolumeCurveScale = br.ReadUInt16();
                if (Bit(22)) VolumeCurvePlateau = br.ReadByte();
                if (Bit(23)) Timer = br.ReadByte();
            }
            if ((Flags & 0xFF000000) != 0xAA000000)
            {
                if (Bit(24)) Unk21 = br.ReadByte();
                if (Bit(25)) PreDelayVariable = br.ReadUInt32();
                if (Bit(26)) StartOffsetVariable = br.ReadUInt32();
                if (Bit(27)) Unk22 = br.ReadUInt16();
                if (Bit(28)) Unk23 = br.ReadUInt16();
                if (Bit(29)) Unk24 = br.ReadUInt16();
                if (Bit(30)) Unk25 = br.ReadUInt16(); //maybe not
                if (Bit(31)) Unk26 = br.ReadUInt16(); //maybe not
            }

            HeaderLength = (uint)(br.BaseStream.Position - pos);

        }

        public void Write(BinaryWriter bw)
        {
            bw.Write(Flags);

            //if (Flags.Value != 0xAAAAAAAA)
            if ((Flags & 0xFF) != 0xAA)
            {
                if (Bit(0)) bw.Write(Flags2);
                if (Bit(1)) bw.Write(Unk01);
                if (Bit(2)) bw.Write(Volume);
                if (Bit(3)) bw.Write(VolumeVariance);
                if (Bit(4)) bw.Write(Pitch);
                if (Bit(5)) bw.Write(PitchVariance);
                if (Bit(6)) bw.Write(Pan);
                if (Bit(7)) bw.Write(PanVariance);
            }
            if ((Flags & 0xFF00) != 0xAA00)
            {
                if (Bit(8)) bw.Write(PreDelay);
                if (Bit(9)) bw.Write(PreDelayVariance);
                if (Bit(10)) bw.Write(StartOffset);
                if (Bit(11)) bw.Write(StartOffsetVariance);
                if (Bit(12)) bw.Write(AttackTime);
                if (Bit(13)) bw.Write(ReleaseTime);
                if (Bit(14)) bw.Write(DopplerFactor);
                if (Bit(15)) bw.Write(Category);
            }
            if ((Flags & 0xFF0000) != 0xAA0000)
            {
                if (Bit(16)) bw.Write(LPFCutoff);
                if (Bit(17)) bw.Write(LPFCutoffVariance);
                if (Bit(18)) bw.Write(HPFCutoff);
                if (Bit(19)) bw.Write(HPFCutoffVariance);
                if (Bit(20)) bw.Write(VolumeCurve);
                if (Bit(21)) bw.Write(VolumeCurveScale);
                if (Bit(22)) bw.Write(VolumeCurvePlateau);
                if (Bit(23)) bw.Write(Timer);
            }
            if ((Flags & 0xFF000000) != 0xAA000000)
            {
                if (Bit(24)) bw.Write(Unk21);
                if (Bit(25)) bw.Write(PreDelayVariable);
                if (Bit(26)) bw.Write(StartOffsetVariable);
                if (Bit(27)) bw.Write(Unk22);
                if (Bit(28)) bw.Write(Unk23);
                if (Bit(29)) bw.Write(Unk24);
                if (Bit(30)) bw.Write(Unk25); //maybe not
                if (Bit(31)) bw.Write(Unk26); //maybe not
            }

        }

        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);

            if ((Flags & 0xFF) != 0xAA)
            {
                if (Bit(0)) RelXml.ValueTag(sb, indent, "Flags2", "0x" + Flags2.Hex);
                if (Bit(1)) RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
                if (Bit(2)) RelXml.ValueTag(sb, indent, "Volume", Volume.ToString());
                if (Bit(3)) RelXml.ValueTag(sb, indent, "VolumeVariance", VolumeVariance.ToString());
                if (Bit(4)) RelXml.ValueTag(sb, indent, "Pitch", Pitch.ToString());
                if (Bit(5)) RelXml.ValueTag(sb, indent, "PitchVariance", PitchVariance.ToString());
                if (Bit(6)) RelXml.ValueTag(sb, indent, "Pan", Pan.ToString());
                if (Bit(7)) RelXml.ValueTag(sb, indent, "PanVariance", PanVariance.ToString());
            }
            if ((Flags & 0xFF00) != 0xAA00)
            {
                if (Bit(8)) RelXml.ValueTag(sb, indent, "PreDelay", PreDelay.ToString());
                if (Bit(9)) RelXml.ValueTag(sb, indent, "PreDelayVariance", PreDelayVariance.ToString());
                if (Bit(10)) RelXml.ValueTag(sb, indent, "StartOffset", StartOffset.ToString());
                if (Bit(11)) RelXml.ValueTag(sb, indent, "StartOffsetVariance", StartOffsetVariance.ToString());
                if (Bit(12)) RelXml.ValueTag(sb, indent, "AttackTime", AttackTime.ToString());
                if (Bit(13)) RelXml.ValueTag(sb, indent, "ReleaseTime", ReleaseTime.ToString());
                if (Bit(14)) RelXml.ValueTag(sb, indent, "DopplerFactor", DopplerFactor.ToString());
                if (Bit(15)) RelXml.StringTag(sb, indent, "Category", RelXml.HashString(Category));
            }
            if ((Flags & 0xFF0000) != 0xAA0000)
            {
                if (Bit(16)) RelXml.ValueTag(sb, indent, "LPFCutoff", LPFCutoff.ToString());
                if (Bit(17)) RelXml.ValueTag(sb, indent, "LPFCutoffVariance", LPFCutoffVariance.ToString());
                if (Bit(18)) RelXml.ValueTag(sb, indent, "HPFCutoff", HPFCutoff.ToString());
                if (Bit(19)) RelXml.ValueTag(sb, indent, "HPFCutoffVariance", HPFCutoffVariance.ToString());
                if (Bit(20)) RelXml.StringTag(sb, indent, "VolumeCurve", RelXml.HashString(VolumeCurve));
                if (Bit(21)) RelXml.ValueTag(sb, indent, "VolumeCurveScale", VolumeCurveScale.ToString());
                if (Bit(22)) RelXml.ValueTag(sb, indent, "VolumeCurvePlateau", VolumeCurvePlateau.ToString());
                if (Bit(23)) RelXml.ValueTag(sb, indent, "Timer", Timer.ToString());
            }
            if ((Flags & 0xFF000000) != 0xAA000000)
            {
                if (Bit(24)) RelXml.ValueTag(sb, indent, "Unk21", Unk21.ToString());
                if (Bit(25)) RelXml.StringTag(sb, indent, "PreDelayVariable", RelXml.HashString(PreDelayVariable));
                if (Bit(26)) RelXml.StringTag(sb, indent, "StartOffsetVariable", RelXml.HashString(StartOffsetVariable));
                if (Bit(27)) RelXml.ValueTag(sb, indent, "Unk22", Unk22.ToString());
                if (Bit(28)) RelXml.ValueTag(sb, indent, "Unk23", Unk23.ToString());
                if (Bit(29)) RelXml.ValueTag(sb, indent, "Unk24", Unk24.ToString());
                if (Bit(30)) RelXml.ValueTag(sb, indent, "Unk25", Unk25.ToString()); //maybe not
                if (Bit(31)) RelXml.ValueTag(sb, indent, "Unk26", Unk26.ToString()); //maybe not
            }

        }
        public void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");

            if ((Flags & 0xFF) != 0xAA)
            {
                if (Bit(0)) Flags2 = Xml.GetChildUIntAttribute(node, "Flags2", "value");
                if (Bit(1)) Unk01 = (ushort)Xml.GetChildUIntAttribute(node, "Unk01", "value");
                if (Bit(2)) Volume = (ushort)Xml.GetChildUIntAttribute(node, "Volume", "value");
                if (Bit(3)) VolumeVariance = (ushort)Xml.GetChildUIntAttribute(node, "VolumeVariance", "value");
                if (Bit(4)) Pitch = (ushort)Xml.GetChildUIntAttribute(node, "Pitch", "value");
                if (Bit(5)) PitchVariance = (ushort)Xml.GetChildUIntAttribute(node, "PitchVariance", "value");
                if (Bit(6)) Pan = (ushort)Xml.GetChildUIntAttribute(node, "Pan", "value");
                if (Bit(7)) PanVariance = (ushort)Xml.GetChildUIntAttribute(node, "PanVariance", "value");
            }
            if ((Flags & 0xFF00) != 0xAA00)
            {
                if (Bit(8)) PreDelay = (ushort)Xml.GetChildUIntAttribute(node, "PreDelay", "value");
                if (Bit(9)) PreDelayVariance = (ushort)Xml.GetChildUIntAttribute(node, "PreDelayVariance", "value");
                if (Bit(10)) StartOffset = Xml.GetChildIntAttribute(node, "StartOffset", "value");
                if (Bit(11)) StartOffsetVariance = Xml.GetChildIntAttribute(node, "StartOffsetVariance", "value");
                if (Bit(12)) AttackTime = (ushort)Xml.GetChildUIntAttribute(node, "AttackTime", "value");
                if (Bit(13)) ReleaseTime = (ushort)Xml.GetChildUIntAttribute(node, "ReleaseTime", "value");
                if (Bit(14)) DopplerFactor = (ushort)Xml.GetChildUIntAttribute(node, "DopplerFactor", "value");
                if (Bit(15)) Category = XmlRel.GetHash(Xml.GetChildInnerText(node, "Category"));
            }
            if ((Flags & 0xFF0000) != 0xAA0000)
            {
                if (Bit(16)) LPFCutoff = (ushort)Xml.GetChildUIntAttribute(node, "LPFCutoff", "value");
                if (Bit(17)) LPFCutoffVariance = (ushort)Xml.GetChildUIntAttribute(node, "LPFCutoffVariance", "value");
                if (Bit(18)) HPFCutoff = (ushort)Xml.GetChildUIntAttribute(node, "HPFCutoff", "value");
                if (Bit(19)) HPFCutoffVariance = (ushort)Xml.GetChildUIntAttribute(node, "HPFCutoffVariance", "value");
                if (Bit(20)) VolumeCurve = XmlRel.GetHash(Xml.GetChildInnerText(node, "VolumeCurve"));
                if (Bit(21)) VolumeCurveScale = (ushort)Xml.GetChildUIntAttribute(node, "VolumeCurveScale", "value");
                if (Bit(22)) VolumeCurvePlateau = (byte)Xml.GetChildUIntAttribute(node, "VolumeCurvePlateau", "value");
                if (Bit(23)) Timer = (byte)Xml.GetChildUIntAttribute(node, "Timer", "value");
            }
            if ((Flags & 0xFF000000) != 0xAA000000)
            {
                if (Bit(24)) Unk21 = (byte)Xml.GetChildUIntAttribute(node, "Unk21", "value");
                if (Bit(25)) PreDelayVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "PreDelayVariable"));
                if (Bit(26)) StartOffsetVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "StartOffsetVariable"));
                if (Bit(27)) Unk22 = (ushort)Xml.GetChildUIntAttribute(node, "Unk22", "value");
                if (Bit(28)) Unk23 = (ushort)Xml.GetChildUIntAttribute(node, "Unk23", "value");
                if (Bit(29)) Unk24 = (ushort)Xml.GetChildUIntAttribute(node, "Unk24", "value");
                if (Bit(30)) Unk25 = (ushort)Xml.GetChildUIntAttribute(node, "Unk25", "value");
                if (Bit(31)) Unk26 = (ushort)Xml.GetChildUIntAttribute(node, "Unk26", "value");
            }

        }


        public uint CalcHeaderLength()
        {
            uint length = 4;
            if ((Flags & 0xFF) != 0xAA)
            {
                if (Bit(0)) length += 4;// Flags2 = br.ReadUInt32();
                if (Bit(1)) length += 2;// Unk01 = br.ReadUInt16();
                if (Bit(2)) length += 2;// Volume = br.ReadUInt16();
                if (Bit(3)) length += 2;// VolumeVariance = br.ReadUInt16();
                if (Bit(4)) length += 2;// Pitch = br.ReadUInt16();
                if (Bit(5)) length += 2;// PitchVariance = br.ReadUInt16();
                if (Bit(6)) length += 2;// Pan = br.ReadUInt16();
                if (Bit(7)) length += 2;// PanVariance = br.ReadUInt16();
            }
            if ((Flags & 0xFF00) != 0xAA00)
            {
                if (Bit(8)) length += 2;// PreDelay = br.ReadUInt16();
                if (Bit(9)) length += 2;// PreDelayVariance = br.ReadUInt16();
                if (Bit(10)) length += 4;// StartOffset = br.ReadUInt32();
                if (Bit(11)) length += 4;// StartOffsetVariance = br.ReadUInt32();
                if (Bit(12)) length += 2;// AttackTime = br.ReadUInt16();
                if (Bit(13)) length += 2;// ReleaseTime = br.ReadUInt16();
                if (Bit(14)) length += 2;// DopplerFactor = br.ReadUInt16();
                if (Bit(15)) length += 4;// CategoryHash = br.ReadUInt32();
            }
            if ((Flags & 0xFF0000) != 0xAA0000)
            {
                if (Bit(16)) length += 2;// LPFCutoff = br.ReadUInt16();
                if (Bit(17)) length += 2;// LPFCutoffVariance = br.ReadUInt16();
                if (Bit(18)) length += 2;// HPFCutoff = br.ReadUInt16();
                if (Bit(19)) length += 2;// HPFCutoffVariance = br.ReadUInt16();
                if (Bit(20)) length += 4;// RolloffCurve = br.ReadUInt32();
                if (Bit(21)) length += 2;// DistanceAttenuation = br.ReadUInt16();
                if (Bit(22)) length += 1;// Unk19 = br.ReadByte();
                if (Bit(23)) length += 1;// Unk20 = br.ReadByte();
            }
            if ((Flags & 0xFF000000) != 0xAA000000)
            {
                if (Bit(24)) length += 1;// Unk21 = br.ReadByte();
                if (Bit(25)) length += 4;// PreDelayParameter = br.ReadUInt32();
                if (Bit(26)) length += 4;// StartOffsetParameter = br.ReadUInt32();
                if (Bit(27)) length += 2;// Unk22 = br.ReadUInt16();
                if (Bit(28)) length += 2;// Unk23 = br.ReadUInt16();
                if (Bit(29)) length += 2;// Unk24 = br.ReadUInt16();
                if (Bit(30)) length += 2;// Unk25 = br.ReadUInt16(); //maybe not
                if (Bit(31)) length += 2;// Unk26 = br.ReadUInt16(); //maybe not
            }

            return length;
        }

        private bool Bit(int b)
        {
            return ((Flags & (1u << b)) != 0);
        }

        public override string ToString()
        {
            return string.Format("{0}: {1}, {2}, {3}, {4}, {5}, {6}, {7}", Flags.Hex, Flags2.Hex, Category, StartOffset, StartOffsetVariance, VolumeCurve, PreDelayVariable, StartOffsetVariable);
        }
    }

    [TC(typeof(EXP))] public class RelSound : RelData
    {
        public RelSoundHeader Header { get; set; }
        public byte ChildSoundsCount { get; set; }
        public RelData[] ChildSounds { get; set; }
        public MetaHash[] ChildSoundsHashes { get; set; }
        public MetaHash[] AudioContainers { get; set; } //Relative path to parent wave container (i.e. "RESIDENT/animals")

        public RelSound(RelFile rel) : base(rel)
        {
        }
        public RelSound(RelData d, BinaryReader br) : base(d)
        {
            Header = new RelSoundHeader(br);
        }

        public void ReadChildSoundsHashes(BinaryReader br)
        {
            ChildSoundsCount = br.ReadByte();
            ChildSoundsHashes = new MetaHash[ChildSoundsCount];
            for (int i = 0; i < ChildSoundsCount; i++)
            {
                ChildSoundsHashes[i] = br.ReadUInt32();
            }
        }
        public void WriteChildSoundsHashes(BinaryWriter bw)
        {
            bw.Write(ChildSoundsCount);
            for (int i = 0; i < ChildSoundsCount; i++)
            {
                bw.Write(ChildSoundsHashes[i]);
            }
        }

        public override void Write(BinaryWriter bw)
        {
            bw.Write(TypeID);
            Header?.Write(bw);
        }

        public override void WriteXml(StringBuilder sb, int indent)
        {
            WriteHeaderXml(sb, indent);
            base.WriteXml(sb, indent);//fallback case
        }

        public void WriteHeaderXml(StringBuilder sb, int indent)
        {
            if (Header == null) return;
            RelXml.OpenTag(sb, indent, "Header");// flags=\"0x" + Header.Flags.Hex + "\"");
            Header.WriteXml(sb, indent + 1);
            RelXml.CloseTag(sb, indent, "Header");
        }

        public void WriteChildSoundsXml(StringBuilder sb, int indent, string nodeName = "ChildSounds")
        {
            if (ChildSoundsHashes == null) return;
            if (ChildSoundsHashes.Length > 0)
            {
                RelXml.OpenTag(sb, indent, nodeName);
                var cind = indent + 1;
                foreach (var hash in ChildSoundsHashes)
                {
                    RelXml.StringTag(sb, cind, "Item", RelXml.HashString(hash));
                }
                RelXml.CloseTag(sb, indent, nodeName);
            }
            else
            {
                RelXml.SelfClosingTag(sb, indent, nodeName);
            }
        }


        public void ReadHeaderXml(XmlNode node)
        {
            var hnode = node.SelectSingleNode("Header");
            if (hnode == null) return;

            Header = new RelSoundHeader(hnode);
        }

        public void ReadChildSoundsXml(XmlNode node, string nodeName = "ChildSounds")
        {
            var atnode = node.SelectSingleNode(nodeName);
            if (atnode == null) return;

            var childnodes = atnode.SelectNodes("Item");
            var childlist = new List<MetaHash>();
            foreach (XmlNode childnode in childnodes)
            {
                childlist.Add(XmlRel.GetHash(childnode.InnerText));
            }
            ChildSoundsHashes = childlist.ToArray();
            ChildSoundsCount = (byte)childlist.Count;
        }

        public uint[] GetChildSoundsHashTableOffsets(uint offset = 0)
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < ChildSoundsCount; i++)
            {
                offsets.Add(offset + 1 + i * 4);
            }
            return offsets.ToArray();
        }

        public override MetaHash[] GetSoundHashes()
        {
            return ChildSoundsHashes;
        }
        public override MetaHash[] GetCurveHashes()
        {
            if ((Header != null) && (Header.VolumeCurve != 0)) return new[] { Header.VolumeCurve };
            return null;
        }
        public override MetaHash[] GetCategoryHashes()
        {
            if ((Header != null) && (Header.Category != 0)) return new[] { Header.Category };
            return null;
        }
    }



    public enum Dat54SoundType : byte
    {
        LoopingSound = 1,
        EnvelopeSound = 2,
        TwinLoopSound = 3,
        SpeechSound = 4,
        OnStopSound = 5,
        WrapperSound = 6,
        SequentialSound = 7,
        StreamingSound = 8,
        RetriggeredOverlappedSound = 9,
        CrossfadeSound = 10,
        CollapsingStereoSound = 11,
        SimpleSound = 12,
        MultitrackSound = 13,
        RandomizedSound = 14,
        EnvironmentSound = 15,
        DynamicEntitySound = 16,
        SequentialOverlapSound = 17,
        ModularSynthSound = 18,
        GranularSound = 19,
        DirectionalSound = 20,
        KineticSound = 21,
        SwitchSound = 22,
        VariableCurveSound = 23,
        VariablePrintValueSound = 24,
        VariableBlockSound = 25,
        IfSound = 26,
        MathOperationSound = 27,
        ParameterTransformSound = 28,
        FluctuatorSound = 29,
        AutomationSound = 30,
        ExternalStreamSound = 31,
        SoundSet = 32,
        AutomationNoteMapSound = 33,
        SoundSetList = 34,
        SoundHashList = 35
    }

    [TC(typeof(EXP))] public class Dat54Sound : RelSound
    {
        public Dat54SoundType Type { get; set; }

        public Dat54Sound(RelFile rel, Dat54SoundType t) : base(rel)
        {
            Type = t;
            TypeID = (byte)t;
        }
        public Dat54Sound(RelData d, BinaryReader br) : base(d, br)
        {
            Type = (Dat54SoundType)TypeID;
        }

        public override void ReadXml(XmlNode node)
        {
            //don't use this as a fallback case! only for reading the header, for use with all defined Dat54Sounds!
            ReadHeaderXml(node);
            //base.ReadXml(node);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            //don't use this as a fallback case! only for writing the header, for use with all defined Dat54Sounds!
            WriteHeaderXml(sb, indent);
            //base.WriteXml(sb, indent);
        }

        public override string ToString()
        {
            return GetBaseString() + ": " + Type.ToString();
        }
    }

    [TC(typeof(EXP))] public class Dat54LoopingSound : Dat54Sound
    {
        public short LoopCount { get; set; } //0x0-0x2 number of times looped
        public short LoopCountVariance { get; set; } //0x2-0x4 loop variance; + or - LoopCount
        public short LoopPoint { get; set; } //0x4-0x6 almost always 0? 1 on synths?
        public MetaHash ChildSound { get; set; } //0x6-0xA
        public MetaHash LoopCountVariable { get; set; } //0xA-0xE

        public Dat54LoopingSound(RelFile rel) : base(rel, Dat54SoundType.LoopingSound)
        { }
        public Dat54LoopingSound(RelData d, BinaryReader br) : base(d, br)
        {
            LoopCount = br.ReadInt16();
            LoopCountVariance = br.ReadInt16();
            LoopPoint = br.ReadInt16();
            ChildSound = br.ReadUInt32();
            ChildSoundsHashes = new[] { ChildSound };
            LoopCountVariable = br.ReadUInt32();
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            LoopCount = (short)Xml.GetChildIntAttribute(node, "LoopCount", "value");
            LoopCountVariance = (short)Xml.GetChildIntAttribute(node, "LoopCountVariance", "value");
            LoopPoint = (short)Xml.GetChildIntAttribute(node, "LoopPoint", "value");
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
            LoopCountVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "LoopCountVariable"));
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "LoopCount", LoopCount.ToString());
            RelXml.ValueTag(sb, indent, "LoopCountVariance", LoopCountVariance.ToString());
            RelXml.ValueTag(sb, indent, "LoopPoint", LoopPoint.ToString());
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
            RelXml.StringTag(sb, indent, "LoopCountVariable", RelXml.HashString(LoopCountVariable));
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(LoopCount);
            bw.Write(LoopCountVariance);
            bw.Write(LoopPoint);
            bw.Write(ChildSound);
            bw.Write(LoopCountVariable);
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 6 };
        }
    }
    [TC(typeof(EXP))] public class Dat54EnvelopeSound : Dat54Sound
    {
        public ushort Attack { get; set; } //0x0-0x2 ADSHR attack in ms. used by PTS or other types.
        public ushort AttackVariance { get; set; } //0x2-0x4 variance of attack in ms.
        public ushort Decay { get; set; } //0x4-0x6 ADSHR decay in ms.
        public ushort DecayVariance { get; set; } //0x6-0x8 variance of decay in ms.
        public byte Sustain { get; set; } //0x8-0x9 ADSHR sustain percentage
        public byte SustainVariance { get; set; } //0x9-0xA variance of sustain percentage.
        public int Hold { get; set; } //0xA-0xE ADSHR hold in ms.
        public ushort HoldVariance { get; set; } //0xE-0x10 variance of hold in ms.
        public int Release { get; set; } //0x10-0x14 ADSHR release in ms.
        public int ReleaseVariance { get; set; } //0x14-0x18 variance of release in ms.
        public MetaHash AttackCurve { get; set; } //0x18-0x1C curves.dat curve shape for attack.
        public MetaHash DecayCurve { get; set; } //0x1C-0x20 curves.dat curve shape for decay.
        public MetaHash ReleaseCurve { get; set; } //0x20-0x24 curves.dat curve shape for release.
        public MetaHash AttackParameter { get; set; } //0x24-0x28 parameter override for attack.
        public MetaHash DecayParameter { get; set; } //0x28-0x2C parameter override for decay.
        public MetaHash SustainParameter { get; set; } //0x2C-0x30 parameter override for sustain.
        public MetaHash HoldParameter { get; set; } //0x30-0x34 parameter override for hold.
        public MetaHash ReleaseParameter { get; set; } //0x34-0x38 parameter override for release.
        public MetaHash ChildSound { get; set; }// audio track 0x38-0x3C
        public int Mode { get; set; } //0x3C-0x40 type of envelope (0 volume, 1 pitch, 2 pan, etc)
        public MetaHash OutputVariable { get; set; } //0x40-0x44 envelope parameter override (mode 5)
        public float OutputRangeMin { get; set; } //0x44-0x48 level min (controls level min before/after attack/release)
        public float OutputRangeMax { get; set; } //0x48-0x4C level max (controls level max between attack/decay)

        public Dat54EnvelopeSound(RelFile rel) : base(rel, Dat54SoundType.EnvelopeSound)
        { }
        public Dat54EnvelopeSound(RelData d, BinaryReader br) : base(d, br)
        {
            Attack = br.ReadUInt16(); //0x0-0x2
            AttackVariance = br.ReadUInt16(); //0x2-0x4
            Decay = br.ReadUInt16(); //0x4-0x6
            DecayVariance = br.ReadUInt16(); //0x6-0x8
            Sustain = br.ReadByte(); //0x8-0x9
            SustainVariance = br.ReadByte(); //0x9-0xA
            Hold = br.ReadInt32(); //0xA-0xE
            HoldVariance = br.ReadUInt16(); //0xE-0x10
            Release = br.ReadInt32(); //0x10-0x14
            ReleaseVariance = br.ReadInt32(); //0x14-0x18
            AttackCurve = br.ReadUInt32(); //0x18-0x1C
            DecayCurve = br.ReadUInt32(); //0x1C-0x20
            ReleaseCurve = br.ReadUInt32(); //0x20-0x24
            AttackParameter = br.ReadUInt32(); //0x24-0x28
            DecayParameter = br.ReadUInt32(); //0x28-0x2C
            SustainParameter = br.ReadUInt32(); //0x2C-0x30
            HoldParameter = br.ReadUInt32(); //0x30-0x34
            ReleaseParameter = br.ReadUInt32(); //0x34-0x38
            ChildSound = br.ReadUInt32(); //0x38-0x3C
            Mode = br.ReadInt32(); //0x3C-0x40
            OutputVariable = br.ReadUInt32(); //0x40-0x44
            OutputRangeMin = br.ReadSingle(); //0x44-0x48
            OutputRangeMax = br.ReadSingle(); //0x48-0x4C
            ChildSoundsHashes = new[] { ChildSound };
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Attack = (ushort)Xml.GetChildUIntAttribute(node, "Attack", "value");
            AttackVariance = (ushort)Xml.GetChildUIntAttribute(node, "AttackVariance", "value");
            Decay = (ushort)Xml.GetChildUIntAttribute(node, "Decay", "value");
            DecayVariance = (ushort)Xml.GetChildUIntAttribute(node, "DecayVariance", "value");
            Sustain = (byte)Xml.GetChildUIntAttribute(node, "Sustain", "value");
            SustainVariance = (byte)Xml.GetChildUIntAttribute(node, "SustainVariance", "value");
            Hold = Xml.GetChildIntAttribute(node, "Hold", "value");
            HoldVariance = (ushort)Xml.GetChildUIntAttribute(node, "HoldVariance", "value");
            Release = Xml.GetChildIntAttribute(node, "Release", "value");
            ReleaseVariance = Xml.GetChildIntAttribute(node, "ReleaseVariance", "value");
            AttackCurve = XmlRel.GetHash(Xml.GetChildInnerText(node, "AttackCurve"));
            DecayCurve = XmlRel.GetHash(Xml.GetChildInnerText(node, "DecayCurve"));
            ReleaseCurve = XmlRel.GetHash(Xml.GetChildInnerText(node, "ReleaseCurve"));
            AttackParameter = XmlRel.GetHash(Xml.GetChildInnerText(node, "AttackParameter"));
            DecayParameter = XmlRel.GetHash(Xml.GetChildInnerText(node, "DecayParameter"));
            SustainParameter = XmlRel.GetHash(Xml.GetChildInnerText(node, "SustainParameter"));
            HoldParameter = XmlRel.GetHash(Xml.GetChildInnerText(node, "HoldParameter"));
            ReleaseParameter = XmlRel.GetHash(Xml.GetChildInnerText(node, "ReleaseParameter"));
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
            Mode = Xml.GetChildIntAttribute(node, "Mode", "value");
            OutputVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "OutputVariable"));
            OutputRangeMin = Xml.GetChildFloatAttribute(node, "OutputRangeMin", "value");
            OutputRangeMax = Xml.GetChildFloatAttribute(node, "OutputRangeMax", "value");
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "Attack", Attack.ToString());
            RelXml.ValueTag(sb, indent, "AttackVariance", AttackVariance.ToString());
            RelXml.ValueTag(sb, indent, "Decay", Decay.ToString());
            RelXml.ValueTag(sb, indent, "DecayVariance", DecayVariance.ToString());
            RelXml.ValueTag(sb, indent, "Sustain", Sustain.ToString());
            RelXml.ValueTag(sb, indent, "SustainVariance", SustainVariance.ToString());
            RelXml.ValueTag(sb, indent, "Hold", Hold.ToString());
            RelXml.ValueTag(sb, indent, "HoldVariance", HoldVariance.ToString());
            RelXml.ValueTag(sb, indent, "Release", Release.ToString());
            RelXml.ValueTag(sb, indent, "ReleaseVariance", ReleaseVariance.ToString());
            RelXml.StringTag(sb, indent, "AttackCurve", RelXml.HashString(AttackCurve));
            RelXml.StringTag(sb, indent, "DecayCurve", RelXml.HashString(DecayCurve));
            RelXml.StringTag(sb, indent, "ReleaseCurve", RelXml.HashString(ReleaseCurve));
            RelXml.StringTag(sb, indent, "AttackParameter", RelXml.HashString(AttackParameter));
            RelXml.StringTag(sb, indent, "DecayParameter", RelXml.HashString(DecayParameter));
            RelXml.StringTag(sb, indent, "SustainParameter", RelXml.HashString(SustainParameter));
            RelXml.StringTag(sb, indent, "HoldParameter", RelXml.HashString(HoldParameter));
            RelXml.StringTag(sb, indent, "ReleaseParameter", RelXml.HashString(ReleaseParameter));
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
            RelXml.ValueTag(sb, indent, "Mode", Mode.ToString());
            RelXml.StringTag(sb, indent, "OutputVariable", RelXml.HashString(OutputVariable));
            RelXml.ValueTag(sb, indent, "OutputRangeMin", FloatUtil.ToString(OutputRangeMin));
            RelXml.ValueTag(sb, indent, "OutputRangeMax", FloatUtil.ToString(OutputRangeMax));
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(Attack); //0x0-0x2
            bw.Write(AttackVariance); //0x2-0x4
            bw.Write(Decay); //0x4-0x6
            bw.Write(DecayVariance); //0x6-0x8
            bw.Write(Sustain); //0x8-0x9
            bw.Write(SustainVariance); //0x9-0xA
            bw.Write(Hold); //0xA-0xE
            bw.Write(HoldVariance); //0xE-0x10
            bw.Write(Release); //0x10-0x14
            bw.Write(ReleaseVariance); //0x14-0x18
            bw.Write(AttackCurve); //0x18-0x1C
            bw.Write(DecayCurve); //0x1C-0x20
            bw.Write(ReleaseCurve); //0x20-0x24
            bw.Write(AttackParameter); //0x24-0x28
            bw.Write(DecayParameter); //0x28-0x2C
            bw.Write(SustainParameter); //0x2C-0x30
            bw.Write(HoldParameter); //0x30-0x34
            bw.Write(ReleaseParameter); //0x34-0x38
            bw.Write(ChildSound); //0x38-0x3C
            bw.Write(Mode); //0x3C-0x40
            bw.Write(OutputVariable); //0x40-0x44
            bw.Write(OutputRangeMin); //0x44-0x48
            bw.Write(OutputRangeMax); //0x48-0x4C
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 56 };
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { AttackCurve, DecayCurve, ReleaseCurve };
        }
    }
    [TC(typeof(EXP))] public class Dat54TwinLoopSound : Dat54Sound
    {
        public ushort MinSwapTime { get; set; } //0x0-0x2 //minimum duration in ms of the two samples, if they are longer they are shortened to this value.
        public ushort MaxSwapTime { get; set; } //0x2-0x4 //maximum duration in ms of the two samples, if they are longer they are shortened to this value.
        public ushort MinCrossfadeTime { get; set; } //0x4-0x6 //minimum amount of crossfade in ms between the two samples. requires a valid crossfade curve.
        public ushort MaxCrossfadeTime { get; set; } //0x6-0x8 //maximum amount of crossfade in ms between the two samples. requires a valid crosfade curve.
        public MetaHash CrossfadeCurve { get; set; } //0x8-0xC //curves.dat curve shape for crossfade between the two samples.
        public MetaHash MinSwapTimeVariable { get; set; } //0xC-0x10 //parameter override for duration min.
        public MetaHash MaxSwapTimeVariable { get; set; } //0x10-0x14 //parameter override for duration max.
        public MetaHash MinCrossfadeTimeVariable { get; set; } //0x14-0x18 //parameter override for crossfade min.
        public MetaHash MaxCrossfadeTimeVariable { get; set; } //0x18-0x1C //parameter override for crossfade max.

        public Dat54TwinLoopSound(RelFile rel) : base(rel, Dat54SoundType.TwinLoopSound)
        { }
        public Dat54TwinLoopSound(RelData d, BinaryReader br) : base(d, br)
        {
            MinSwapTime = br.ReadUInt16();
            MaxSwapTime = br.ReadUInt16();
            MinCrossfadeTime = br.ReadUInt16();
            MaxCrossfadeTime = br.ReadUInt16();
            CrossfadeCurve = br.ReadUInt32();
            MinSwapTimeVariable = br.ReadUInt32();
            MaxSwapTimeVariable = br.ReadUInt32();
            MinCrossfadeTimeVariable = br.ReadUInt32();
            MaxCrossfadeTimeVariable = br.ReadUInt32();

            ReadChildSoundsHashes(br);
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            MinSwapTime = (ushort)Xml.GetChildUIntAttribute(node, "MinSwapTime", "value");
            MaxSwapTime = (ushort)Xml.GetChildUIntAttribute(node, "MaxSwapTime", "value");
            MinCrossfadeTime = (ushort)Xml.GetChildUIntAttribute(node, "MinCrossfadeTime", "value");
            MaxCrossfadeTime = (ushort)Xml.GetChildUIntAttribute(node, "MaxCrossfadeTime", "value");
            CrossfadeCurve = XmlRel.GetHash(Xml.GetChildInnerText(node, "CrossfadeCurve"));
            MinSwapTimeVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "MinSwapTimeVariable"));
            MaxSwapTimeVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "MaxSwapTimeVariable"));
            MinCrossfadeTimeVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "MinCrossfadeTimeVariable"));
            MaxCrossfadeTimeVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "MaxCrossfadeTimeVariable"));
            ReadChildSoundsXml(node);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "MinSwapTime", MinSwapTime.ToString());
            RelXml.ValueTag(sb, indent, "MaxSwapTime", MaxSwapTime.ToString());
            RelXml.ValueTag(sb, indent, "MinCrossfadeTime", MinCrossfadeTime.ToString());
            RelXml.ValueTag(sb, indent, "MaxCrossfadeTime", MaxCrossfadeTime.ToString());
            RelXml.StringTag(sb, indent, "CrossfadeCurve", RelXml.HashString(CrossfadeCurve));
            RelXml.StringTag(sb, indent, "MinSwapTimeVariable", RelXml.HashString(MinSwapTimeVariable));
            RelXml.StringTag(sb, indent, "MaxSwapTimeVariable", RelXml.HashString(MaxSwapTimeVariable));
            RelXml.StringTag(sb, indent, "MinCrossfadeTimeVariable", RelXml.HashString(MinCrossfadeTimeVariable));
            RelXml.StringTag(sb, indent, "MaxCrossfadeTimeVariable", RelXml.HashString(MaxCrossfadeTimeVariable));
            WriteChildSoundsXml(sb, indent);
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(MinSwapTime);
            bw.Write(MaxSwapTime);
            bw.Write(MinCrossfadeTime);
            bw.Write(MaxCrossfadeTime);
            bw.Write(CrossfadeCurve);
            bw.Write(MinSwapTimeVariable);
            bw.Write(MaxSwapTimeVariable);
            bw.Write(MinCrossfadeTimeVariable);
            bw.Write(MaxCrossfadeTimeVariable);

            WriteChildSoundsHashes(bw);
        }
        public override uint[] GetHashTableOffsets()
        {
            return GetChildSoundsHashTableOffsets(28);
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { CrossfadeCurve };
        }
    }
    [TC(typeof(EXP))] public class Dat54SpeechSound : Dat54Sound
    {
        public int LastVariation { get; set; } //maybe file index?
        public int SpeechUnkInt1 { get; set; } //0x4-0x8
        public MetaHash VoiceName { get; set; } //0x8-0xC
        public string ContextName { get; set; } //0xD-...

        public Dat54SpeechSound(RelFile rel) : base(rel, Dat54SoundType.SpeechSound)
        { }
        public Dat54SpeechSound(RelData d, BinaryReader br) : base(d, br)
        {
            LastVariation = br.ReadInt32();
            SpeechUnkInt1 = br.ReadInt32();
            VoiceName = br.ReadUInt32();
            ContextName = br.ReadString();
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            LastVariation = Xml.GetChildIntAttribute(node, "LastVariation", "value");
            SpeechUnkInt1 = Xml.GetChildIntAttribute(node, "SpeechUnkInt1", "value");
            VoiceName = XmlRel.GetHash(Xml.GetChildInnerText(node, "VoiceName"));
            ContextName = Xml.GetChildInnerText(node, "ContextName");
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "LastVariation", LastVariation.ToString());
            RelXml.ValueTag(sb, indent, "SpeechUnkInt1", SpeechUnkInt1.ToString());
            RelXml.StringTag(sb, indent, "VoiceName", RelXml.HashString(VoiceName));
            RelXml.StringTag(sb, indent, "ContextName", ContextName);
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(LastVariation);
            bw.Write(SpeechUnkInt1);
            bw.Write(VoiceName);
            bw.Write(ContextName);
        }
    }
    [TC(typeof(EXP))] public class Dat54OnStopSound : Dat54Sound
    {
        public MetaHash ChildSound { get; set; }
        public MetaHash StopSound { get; set; } //plays once childsound is finished playing (enveloped or single sample, no loops)
        public MetaHash FinishedSound { get; set; } //plays when the onstop entry is empty or invalid

        public Dat54OnStopSound(RelFile rel) : base(rel, Dat54SoundType.OnStopSound)
        { }
        public Dat54OnStopSound(RelData d, BinaryReader br) : base(d, br)
        {
            ChildSound = br.ReadUInt32();
            StopSound = br.ReadUInt32();
            FinishedSound = br.ReadUInt32();
            ChildSoundsHashes = new[] { ChildSound, StopSound, FinishedSound };
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
            StopSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "StopSound"));
            FinishedSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "FinishedSound"));
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
            RelXml.StringTag(sb, indent, "StopSound", RelXml.HashString(StopSound));
            RelXml.StringTag(sb, indent, "FinishedSound", RelXml.HashString(FinishedSound));
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(ChildSound);
            bw.Write(StopSound);
            bw.Write(FinishedSound);
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0, 4, 8 };
        }
    }
    [TC(typeof(EXP))] public class Dat54WrapperSound : Dat54Sound
    {
        public MetaHash ChildSound { get; set; } //0x0-0x4
        public int LastPlayTime { get; set; } //0x4-0x8  // maybe start delay?
        public MetaHash FallBackSound { get; set; } //0x8-0xC sound falled back on if main sound not found
        public short MinRepeatTime { get; set; } //0xC-0xE  // [camxx:] My guess is that this is related to the time at which a child sound should start playin (or the length of the sound).
        public byte VariableCount { get; set; }
        public MetaHash[] VariableNames { get; set; } //0xF // apply any variables here. seems to have been a header field in IV but merged only with wrapper sound in V.
        public byte[] VariableValues { get; set; } // ...

        public Dat54WrapperSound(RelFile rel) : base(rel, Dat54SoundType.WrapperSound)
        { }
        public Dat54WrapperSound(RelData d, BinaryReader br) : base(d, br)
        {
            ChildSound = br.ReadUInt32();
            LastPlayTime = br.ReadInt32();
            FallBackSound = br.ReadUInt32();
            MinRepeatTime = br.ReadInt16();
            VariableCount = br.ReadByte();
            VariableNames = new MetaHash[VariableCount];
            for (int i = 0; i < VariableCount; i++)
            {
                VariableNames[i] = br.ReadUInt32();
            }
            VariableValues = br.ReadBytes(VariableCount);

            ChildSoundsHashes = new[] { ChildSound, FallBackSound };
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
            LastPlayTime = Xml.GetChildIntAttribute(node, "LastPlayTime", "value");
            FallBackSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "FallBackSound"));
            MinRepeatTime = (short)Xml.GetChildIntAttribute(node, "MinRepeatTime", "value");
            var vnode = node.SelectSingleNode("Variables");
            if (vnode != null)
            {
                var inodes = vnode.SelectNodes("Item");
                if (inodes?.Count > 0)
                {
                    var nlist = new List<MetaHash>();
                    var vlist = new List<byte>();
                    foreach (XmlNode inode in inodes)
                    {
                        nlist.Add(XmlRel.GetHash(Xml.GetStringAttribute(inode, "name")));
                        vlist.Add((byte)Xml.GetIntAttribute(inode, "value"));
                    }
                    VariableCount = (byte)nlist.Count;
                    VariableNames = nlist.ToArray();
                    VariableValues = vlist.ToArray();
                }
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
            RelXml.ValueTag(sb, indent, "LastPlayTime", LastPlayTime.ToString());
            RelXml.StringTag(sb, indent, "FallBackSound", RelXml.HashString(FallBackSound));
            RelXml.ValueTag(sb, indent, "MinRepeatTime", MinRepeatTime.ToString());
            if (VariableNames?.Length > 0)
            {
                RelXml.OpenTag(sb, indent, "Variables");
                var cind = indent + 1;
                for (int i = 0; i < VariableCount; i++)
                {
                    var iname = RelXml.HashString(VariableNames[i]);
                    var ival = VariableValues[i].ToString();
                    RelXml.SelfClosingTag(sb, cind, "Item name=\"" + iname + "\" value=\"" + ival + "\"");
                }
                RelXml.CloseTag(sb, indent, "Variables");
            }
            else
            {
                RelXml.SelfClosingTag(sb, indent, "Variables");
            }
            WriteChildSoundsXml(sb, indent);
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(ChildSound);
            bw.Write(LastPlayTime);
            bw.Write(FallBackSound);
            bw.Write(MinRepeatTime);
            bw.Write(VariableCount);
            for (int i = 0; i < VariableCount; i++)
            {
                bw.Write(VariableNames[i]);
            }
            if (VariableValues != null)
            {
                bw.Write(VariableValues);
            }
            else
            { }
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0, 8 };
        }
    }
    [TC(typeof(EXP))] public class Dat54SequentialSound : Dat54Sound
    {
        public Dat54SequentialSound(RelFile rel) : base(rel, Dat54SoundType.SequentialSound)
        { }
        public Dat54SequentialSound(RelData d, BinaryReader br) : base(d, br)
        {
            ReadChildSoundsHashes(br);
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ReadChildSoundsXml(node);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            WriteChildSoundsXml(sb, indent);
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            WriteChildSoundsHashes(bw);
        }
        public override uint[] GetHashTableOffsets()
        {
            return GetChildSoundsHashTableOffsets();
        }
    }
    [TC(typeof(EXP))] public class Dat54StreamingSound : Dat54Sound
    {
        public int Duration { get; set; } //0x0-0x4

        public Dat54StreamingSound(RelFile rel) : base(rel, Dat54SoundType.StreamingSound)
        { }
        public Dat54StreamingSound(RelData d, BinaryReader br) : base(d, br)
        {
            Duration = br.ReadInt32();

            ReadChildSoundsHashes(br);
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Duration = Xml.GetChildIntAttribute(node, "Duration", "value");
            ReadChildSoundsXml(node);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "Duration", Duration.ToString());
            WriteChildSoundsXml(sb, indent);
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(Duration);
            WriteChildSoundsHashes(bw);
        }
        public override uint[] GetHashTableOffsets()
        {
            return GetChildSoundsHashTableOffsets(4);
        }
    }
    [TC(typeof(EXP))] public class Dat54RetriggeredOverlappedSound : Dat54Sound
    {
        public ushort LoopCount { get; set; } //0x0-0x2 number of times to repeat. includes start and tail sounds if defined
        public ushort LoopCountVariance { get; set; } //0x2-0x4 variance of retrigger count
        public ushort DelayTime { get; set; } //0x4-0x6 amount of delay in ms between the start of the retriggers
        public ushort DelayTimeVariance { get; set; } // 0x6-0x8 variance of delay
        public MetaHash LoopCountVariable { get; set; } //0x8-0xC parameter override for retrigger count
        public MetaHash DelayTimeVariable { get; set; } //0xC-0x10 parameter override for delay
        public MetaHash StartSound { get; set; } // sound to play on first instance
        public MetaHash RetriggerSound { get; set; } //sound to retrigger
        public MetaHash StopSound { get; set; }  //sound to play on last instance

        public Dat54RetriggeredOverlappedSound(RelFile rel) : base(rel, Dat54SoundType.RetriggeredOverlappedSound)
        { }
        public Dat54RetriggeredOverlappedSound(RelData d, BinaryReader br) : base(d, br)
        {
            LoopCount = br.ReadUInt16();
            LoopCountVariance = br.ReadUInt16();
            DelayTime = br.ReadUInt16();
            DelayTimeVariance = br.ReadUInt16();
            LoopCountVariable = br.ReadUInt32();
            DelayTimeVariable = br.ReadUInt32();
            StartSound = br.ReadUInt32();
            RetriggerSound = br.ReadUInt32();
            StopSound = br.ReadUInt32();
            ChildSoundsHashes = new[] { StartSound, RetriggerSound, StopSound };
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            LoopCount = (ushort)Xml.GetChildUIntAttribute(node, "LoopCount", "value");
            LoopCountVariance = (ushort)Xml.GetChildUIntAttribute(node, "LoopCountVariance", "value");
            DelayTime = (ushort)Xml.GetChildUIntAttribute(node, "DelayTime", "value");
            DelayTimeVariance = (ushort)Xml.GetChildUIntAttribute(node, "DelayTimeVariance", "value");
            LoopCountVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "LoopCountVariable"));
            DelayTimeVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "DelayTimeVariable"));
            StartSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "StartSound"));
            RetriggerSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "RetriggerSound"));
            StopSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "StopSound"));
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "LoopCount", LoopCount.ToString());
            RelXml.ValueTag(sb, indent, "LoopCountVariance", LoopCountVariance.ToString());
            RelXml.ValueTag(sb, indent, "DelayTime", DelayTime.ToString());
            RelXml.ValueTag(sb, indent, "DelayTimeVariance", DelayTimeVariance.ToString());
            RelXml.StringTag(sb, indent, "LoopCountVariable", RelXml.HashString(LoopCountVariable));
            RelXml.StringTag(sb, indent, "DelayTimeVariable", RelXml.HashString(DelayTimeVariable));
            RelXml.StringTag(sb, indent, "StartSound", RelXml.HashString(StartSound));
            RelXml.StringTag(sb, indent, "RetriggerSound", RelXml.HashString(RetriggerSound));
            RelXml.StringTag(sb, indent, "StopSound", RelXml.HashString(StopSound));
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(LoopCount);
            bw.Write(LoopCountVariance);
            bw.Write(DelayTime);
            bw.Write(DelayTimeVariance);
            bw.Write(LoopCountVariable);
            bw.Write(DelayTimeVariable);
            bw.Write(StartSound);
            bw.Write(RetriggerSound);
            bw.Write(StopSound);
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 16, 20, 24 };
        }
    }
    [TC(typeof(EXP))] public class Dat54CrossfadeSound : Dat54Sound
    {
        public MetaHash FadeOutSound { get; set; }
        public MetaHash FadeInSound { get; set; }
        public byte CrossfadeUnkByte { get; set; } //0x8-0x9
        public float UnkFloat0 { get; set; } //0x9-0xD
        public float UnkFloat1 { get; set; } //0xD-0x11
        public int CrossfadeUnkInt { get; set; } //0xD-0x15
        public MetaHash UnkCurvesHash { get; set; } //0x15-0x19
        public MetaHash ParameterHash0 { get; set; } //0x19-0x1D
        public MetaHash ParameterHash1 { get; set; } //0x1D-0x21
        public MetaHash ParameterHash2 { get; set; } //0x21-0x25
        public MetaHash ParameterHash3 { get; set; } //0x25-0x29
        public MetaHash ParameterHash4 { get; set; } //0x29-0x2D

        public Dat54CrossfadeSound(RelFile rel) : base(rel, Dat54SoundType.CrossfadeSound)
        { }
        public Dat54CrossfadeSound(RelData d, BinaryReader br) : base(d, br)
        {
            FadeOutSound = br.ReadUInt32();
            FadeInSound = br.ReadUInt32();
            ChildSoundsHashes = new[] { FadeOutSound, FadeInSound };
            CrossfadeUnkByte = br.ReadByte();
            UnkFloat0 = br.ReadSingle();
            UnkFloat1 = br.ReadSingle();
            CrossfadeUnkInt = br.ReadInt32();
            UnkCurvesHash = br.ReadUInt32();
            ParameterHash0 = br.ReadUInt32();
            ParameterHash1 = br.ReadUInt32();
            ParameterHash2 = br.ReadUInt32();
            ParameterHash3 = br.ReadUInt32();
            ParameterHash4 = br.ReadUInt32();
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            FadeOutSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "FadeOutSound"));
            FadeInSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "FadeInSound"));
            CrossfadeUnkByte = (byte)Xml.GetChildUIntAttribute(node, "CrossfadeUnkByte", "value");
            UnkFloat0 = Xml.GetChildFloatAttribute(node, "UnkFloat0", "value");
            UnkFloat1 = Xml.GetChildFloatAttribute(node, "UnkFloat1", "value");
            CrossfadeUnkInt = Xml.GetChildIntAttribute(node, "CrossfadeUnkInt", "value");
            UnkCurvesHash = XmlRel.GetHash(Xml.GetChildInnerText(node, "UnkCurvesHash"));
            ParameterHash0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ParameterHash0"));
            ParameterHash1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ParameterHash1"));
            ParameterHash2 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ParameterHash2"));
            ParameterHash3 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ParameterHash3"));
            ParameterHash4 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ParameterHash4"));
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "FadeOutSound", RelXml.HashString(FadeOutSound));
            RelXml.StringTag(sb, indent, "FadeInSound", RelXml.HashString(FadeInSound));
            RelXml.ValueTag(sb, indent, "CrossfadeUnkByte", CrossfadeUnkByte.ToString());
            RelXml.ValueTag(sb, indent, "UnkFloat0", FloatUtil.ToString(UnkFloat0));
            RelXml.ValueTag(sb, indent, "UnkFloat1", FloatUtil.ToString(UnkFloat1));
            RelXml.ValueTag(sb, indent, "CrossfadeUnkInt", CrossfadeUnkInt.ToString());
            RelXml.StringTag(sb, indent, "UnkCurvesHash", RelXml.HashString(UnkCurvesHash));
            RelXml.StringTag(sb, indent, "ParameterHash0", RelXml.HashString(ParameterHash0));
            RelXml.StringTag(sb, indent, "ParameterHash1", RelXml.HashString(ParameterHash1));
            RelXml.StringTag(sb, indent, "ParameterHash2", RelXml.HashString(ParameterHash2));
            RelXml.StringTag(sb, indent, "ParameterHash3", RelXml.HashString(ParameterHash3));
            RelXml.StringTag(sb, indent, "ParameterHash4", RelXml.HashString(ParameterHash4));
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(FadeOutSound);
            bw.Write(FadeInSound);
            bw.Write(CrossfadeUnkByte);
            bw.Write(UnkFloat0);
            bw.Write(UnkFloat1);
            bw.Write(CrossfadeUnkInt);
            bw.Write(UnkCurvesHash);
            bw.Write(ParameterHash0);
            bw.Write(ParameterHash1);
            bw.Write(ParameterHash2);
            bw.Write(ParameterHash3);
            bw.Write(ParameterHash4);
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0, 4 };
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { UnkCurvesHash };
        }
    }
    [TC(typeof(EXP))] public class Dat54CollapsingStereoSound : Dat54Sound
    {
        public MetaHash LeftSound { get; set; }
        public MetaHash RightSound { get; set; }
        public float MinDistance { get; set; }
        public float MaxDistance { get; set; }
        public MetaHash MinDistanceVariable { get; set; } //0x10-0x14
        public MetaHash MaxDistanceVariable { get; set; } //0x14-0x18
        public MetaHash CrossfadeOverrideVariable { get; set; } //0x18-0x1C
        public MetaHash ParameterHash3 { get; set; } //0x1C-0x20
        public MetaHash ParameterHash4 { get; set; } //0x20-0x24
        public int UnkInt { get; set; } //0x24-0x28
        public MetaHash ParameterHash5 { get; set; } //0x28-0x2C
        public byte Mode { get; set; } //0x2c-0x2D

        public Dat54CollapsingStereoSound(RelFile rel) : base(rel, Dat54SoundType.CollapsingStereoSound)
        { }
        public Dat54CollapsingStereoSound(RelData d, BinaryReader br) : base(d, br)
        {
            LeftSound = br.ReadUInt32();
            RightSound = br.ReadUInt32();
            ChildSoundsHashes = new[] { LeftSound, RightSound };
            MinDistance = br.ReadSingle(); //0x8
            MaxDistance = br.ReadSingle(); //0xC
            MinDistanceVariable = br.ReadUInt32(); //0x10
            MaxDistanceVariable = br.ReadUInt32(); //0x14
            CrossfadeOverrideVariable = br.ReadUInt32(); //0x18
            ParameterHash3 = br.ReadUInt32(); //0x1C
            ParameterHash4 = br.ReadUInt32(); //0x20
            UnkInt = br.ReadInt32(); //0x24-0x28
            ParameterHash5 = br.ReadUInt32(); //0x28-0x2C
            Mode = br.ReadByte(); //0x2C-0x2D
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            LeftSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "LeftSound"));
            RightSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "RightSound"));
            MinDistance = Xml.GetChildFloatAttribute(node, "MinDistance", "value");
            MaxDistance = Xml.GetChildFloatAttribute(node, "MaxDistance", "value");
            MinDistanceVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "MinDistanceVariable"));
            MaxDistanceVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "MaxDistanceVariable"));
            CrossfadeOverrideVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "CrossfadeOverrideVariable"));
            ParameterHash3 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ParameterHash3"));
            ParameterHash4 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ParameterHash4"));
            UnkInt = Xml.GetChildIntAttribute(node, "UnkInt", "value");
            ParameterHash5 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ParameterHash5"));
            Mode = (byte)Xml.GetChildUIntAttribute(node, "Mode", "value");
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "LeftSound", RelXml.HashString(LeftSound));
            RelXml.StringTag(sb, indent, "RightSound", RelXml.HashString(RightSound));
            RelXml.ValueTag(sb, indent, "MinDistance", FloatUtil.ToString(MinDistance));
            RelXml.ValueTag(sb, indent, "MaxDistance", FloatUtil.ToString(MaxDistance));
            RelXml.StringTag(sb, indent, "MinDistanceVariable", RelXml.HashString(MinDistanceVariable));
            RelXml.StringTag(sb, indent, "MaxDistanceVariable", RelXml.HashString(MaxDistanceVariable));
            RelXml.StringTag(sb, indent, "CrossfadeOverrideVariable", RelXml.HashString(CrossfadeOverrideVariable));
            RelXml.StringTag(sb, indent, "ParameterHash3", RelXml.HashString(ParameterHash3));
            RelXml.StringTag(sb, indent, "ParameterHash4", RelXml.HashString(ParameterHash4));
            RelXml.ValueTag(sb, indent, "UnkInt", UnkInt.ToString());
            RelXml.StringTag(sb, indent, "ParameterHash5", RelXml.HashString(ParameterHash5));
            RelXml.ValueTag(sb, indent, "Mode", Mode.ToString());
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(LeftSound);
            bw.Write(RightSound);
            bw.Write(MinDistance); //0x8
            bw.Write(MaxDistance); //0xC
            bw.Write(MinDistanceVariable); //0x10
            bw.Write(MaxDistanceVariable); //0x14
            bw.Write(CrossfadeOverrideVariable); //0x18
            bw.Write(ParameterHash3); //0x1C
            bw.Write(ParameterHash4); //0x20
            bw.Write(UnkInt); //0x24-0x28
            bw.Write(ParameterHash5); //0x28-0x2C
            bw.Write(Mode); //0x2C-0x2D
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0, 4 };
        }
    }
    [TC(typeof(EXP))] public class Dat54SimpleSound : Dat54Sound
    {
        public MetaHash ContainerName { get; set; } //Relative path to parent wave container (i.e. "RESIDENT/animals")
        public MetaHash FileName { get; set; } //Name of the .wav file
        public byte WaveSlotNum { get; set; } //Internal index of wave (.awc) container

        public Dat54SimpleSound(RelFile rel) : base(rel, Dat54SoundType.SimpleSound)
        { }
        public Dat54SimpleSound(RelData d, BinaryReader br) : base(d, br)
        {
            ContainerName = br.ReadUInt32();
            AudioContainers = new[] { ContainerName };
            FileName = br.ReadUInt32();
            WaveSlotNum = br.ReadByte();
            if (br.BaseStream.Position < br.BaseStream.Length)
            { }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ContainerName = XmlRel.GetHash(Xml.GetChildInnerText(node, "ContainerName"));
            FileName = XmlRel.GetHash(Xml.GetChildInnerText(node, "FileName"));
            WaveSlotNum = (byte)Xml.GetChildUIntAttribute(node, "WaveSlotNum", "value");
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "ContainerName", RelXml.HashString(ContainerName));
            RelXml.StringTag(sb, indent, "FileName", RelXml.HashString(FileName));
            RelXml.ValueTag(sb, indent, "WaveSlotNum", WaveSlotNum.ToString());
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(ContainerName);
            bw.Write(FileName);
            bw.Write(WaveSlotNum);
        }
        public override uint[] GetPackTableOffsets()
        {
            return new uint[] { 0 };
        }
    }
    [TC(typeof(EXP))] public class Dat54MultitrackSound : Dat54Sound
    {
        public Dat54MultitrackSound(RelFile rel) : base(rel, Dat54SoundType.MultitrackSound)
        { }
        public Dat54MultitrackSound(RelData d, BinaryReader br) : base(d, br)
        {
            ReadChildSoundsHashes(br);
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ReadChildSoundsXml(node);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            WriteChildSoundsXml(sb, indent);
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            WriteChildSoundsHashes(bw);
        }
        public override uint[] GetHashTableOffsets()
        {
            return GetChildSoundsHashTableOffsets();
        }
    }
    [TC(typeof(EXP))] public class Dat54RandomizedSound : Dat54Sound
    {
        public byte HistoryIndex { get; set; } //0x0-0x1 retricts the randomization range?
        public byte HistorySpaceCount { get; set; } //0x1-0x2
        public byte[] HistorySpace { get; set; } //seem to prevent randomization from playing the same sound twice in a row?
        public byte VariationsCount { get; set; }
        public float[] VariationsValues { get; set; } //probability..?

        public Dat54RandomizedSound(RelFile rel) : base(rel, Dat54SoundType.RandomizedSound)
        { }
        public Dat54RandomizedSound(RelData d, BinaryReader br) : base(d, br)
        {
            HistoryIndex = br.ReadByte();
            HistorySpaceCount = br.ReadByte();
            HistorySpace = br.ReadBytes(HistorySpaceCount);
            VariationsCount = br.ReadByte();
            ChildSoundsHashes = new MetaHash[VariationsCount];
            VariationsValues = new float[VariationsCount];
            for (int i = 0; i < VariationsCount; i++)
            {
                ChildSoundsHashes[i] = br.ReadUInt32();
                VariationsValues[i] = br.ReadSingle();
            }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            HistoryIndex = (byte)Xml.GetChildUIntAttribute(node, "HistoryIndex", "value");
            HistorySpace = Xml.GetChildRawByteArray(node, "HistorySpace");
            HistorySpaceCount = (byte)HistorySpace.Length;
            var vnode = node.SelectSingleNode("Variations");
            if (vnode != null)
            {
                var inodes = vnode.SelectNodes("Item");
                if (inodes?.Count > 0)
                {
                    var nlist = new List<MetaHash>();
                    var vlist = new List<float>();
                    foreach (XmlNode inode in inodes)
                    {
                        nlist.Add(XmlRel.GetHash(Xml.GetStringAttribute(inode, "name")));
                        vlist.Add(Xml.GetFloatAttribute(inode, "value"));
                    }
                    VariationsCount = (byte)nlist.Count;
                    ChildSoundsHashes = nlist.ToArray();
                    VariationsValues = vlist.ToArray();
                }
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "HistoryIndex", HistoryIndex.ToString());
            RelXml.WriteRawArray(sb, HistorySpace, indent, "HistorySpace", "", RelXml.FormatHexByte, 16);
            if (VariationsCount > 0)
            {
                RelXml.OpenTag(sb, indent, "Variations");
                var cind = indent + 1;
                for (int i = 0; i < VariationsCount; i++)
                {
                    var iname = RelXml.HashString(ChildSoundsHashes[i]);
                    var ival = FloatUtil.ToString(VariationsValues[i]);
                    RelXml.SelfClosingTag(sb, cind, "Item name=\"" + iname + "\" value=\"" + ival + "\"");
                }
                RelXml.CloseTag(sb, indent, "Variations");
            }
            else
            {
                RelXml.SelfClosingTag(sb, indent, "Variations");
            }
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(HistoryIndex);
            bw.Write(HistorySpaceCount);
            bw.Write(HistorySpace);
            bw.Write(VariationsCount);
            for (int i = 0; i < VariationsCount; i++)
            {
                bw.Write(ChildSoundsHashes[i]);
                bw.Write(VariationsValues[i]);
            }
        }
        public override uint[] GetHashTableOffsets()
        {
            var offset = 3u + HistorySpaceCount;
            var offsets = new List<uint>();
            for (uint i = 0; i < VariationsCount; i++)
            {
                offsets.Add(offset + i * 8);
            }
            return offsets.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat54EnvironmentSound : Dat54Sound
    {
        public byte ChannelID { get; set; }

        public Dat54EnvironmentSound(RelFile rel) : base(rel, Dat54SoundType.EnvironmentSound)
        { }
        public Dat54EnvironmentSound(RelData d, BinaryReader br) : base(d, br)
        {
            ChannelID = br.ReadByte();
            if (br.BaseStream.Position < br.BaseStream.Length)
            { }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ChannelID = (byte)Xml.GetChildUIntAttribute(node, "ChannelID", "value");
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "ChannelID", ChannelID.ToString());
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(ChannelID);
        }
    }
    [TC(typeof(EXP))] public class Dat54DynamicEntitySound : Dat54Sound
    {
        public byte ItemCount { get; set; }
        public MetaHash[] Items { get; set; }

        public Dat54DynamicEntitySound(RelFile rel) : base(rel, Dat54SoundType.DynamicEntitySound)
        { }
        public Dat54DynamicEntitySound(RelData d, BinaryReader br) : base(d, br)
        {
            ItemCount = br.ReadByte();
            Items = new MetaHash[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = br.ReadUInt32();
            }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Items = XmlRel.ReadHashItemArray(node, "Items");
            ItemCount = (byte)(Items?.Length ?? 0);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.WriteHashItemArray(sb, Items, indent, "Items");
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                bw.Write(Items[i]);
            }
        }
    }
    [TC(typeof(EXP))] public class Dat54SequentialOverlapSound : Dat54Sound
    {
        public ushort DelayTime { get; set; }
        public MetaHash DelayTimeVariable { get; set; } //0x2-0x6
        public MetaHash SequenceDirection { get; set; } //0x6-0xA

        public Dat54SequentialOverlapSound(RelFile rel) : base(rel, Dat54SoundType.SequentialOverlapSound)
        { }
        public Dat54SequentialOverlapSound(RelData d, BinaryReader br) : base(d, br)
        {
            DelayTime = br.ReadUInt16();
            DelayTimeVariable = br.ReadUInt32();
            SequenceDirection = br.ReadUInt32();

            ReadChildSoundsHashes(br);
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            DelayTime = (ushort)Xml.GetChildUIntAttribute(node, "DelayTime", "value");
            DelayTimeVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "DelayTimeVariable"));
            SequenceDirection = XmlRel.GetHash(Xml.GetChildInnerText(node, "SequenceDirection"));

            ReadChildSoundsXml(node);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "DelayTime", DelayTime.ToString());
            RelXml.StringTag(sb, indent, "DelayTimeVariable", RelXml.HashString(DelayTimeVariable));
            RelXml.StringTag(sb, indent, "SequenceDirection", RelXml.HashString(SequenceDirection));

            WriteChildSoundsXml(sb, indent);
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(DelayTime);
            bw.Write(DelayTimeVariable);
            bw.Write(SequenceDirection);
            WriteChildSoundsHashes(bw);
        }
        public override uint[] GetHashTableOffsets()
        {
            return GetChildSoundsHashTableOffsets(10);
        }
    }
    [TC(typeof(EXP))] public class Dat54ModularSynthSound : Dat54Sound
    {
        public MetaHash SynthSound { get; set; } //0x0-0x4
        public MetaHash SynthPreset { get; set; } //0x4-0x8
        public float PlaybackTimeLimit { get; set; } //0x8-0xC
        public int UnkInt { get; set; } //0xC-0x10
        public int TrackCount { get; set; }
        public int ExposedVariablesCount { get; set; }
        public Dat54ModularSynthSoundVariable[] ExposedVariables { get; set; } //0x28-..

        public Dat54ModularSynthSound(RelFile rel) : base(rel, Dat54SoundType.ModularSynthSound)
        { }
        public Dat54ModularSynthSound(RelData d, BinaryReader br) : base(d, br)
        {
            SynthSound = br.ReadUInt32(); //0x0-0x4
            SynthPreset = br.ReadUInt32(); //0x4-0x8
            PlaybackTimeLimit = br.ReadSingle(); //0x8-0xC
            UnkInt = br.ReadInt32(); //0xC-0x10
            TrackCount = br.ReadInt32(); //0x10-0x14
            ChildSoundsHashes = new MetaHash[4];
            for (int i = 0; i < 4; i++)
            {
                ChildSoundsHashes[i] = br.ReadUInt32();
            }
            ExposedVariablesCount = br.ReadInt32();
            ExposedVariables = new Dat54ModularSynthSoundVariable[ExposedVariablesCount];
            for (int i = 0; i < ExposedVariablesCount; i++)
            {
                ExposedVariables[i] = new Dat54ModularSynthSoundVariable(br);
            }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            SynthSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "SynthSound"));
            SynthPreset = XmlRel.GetHash(Xml.GetChildInnerText(node, "SynthPreset"));
            PlaybackTimeLimit = Xml.GetChildFloatAttribute(node, "PlaybackTimeLimit", "value");
            UnkInt = Xml.GetChildIntAttribute(node, "UnkInt", "value");
            TrackCount = Xml.GetChildIntAttribute(node, "TrackCount", "value");
            ReadChildSoundsXml(node, "EnvironmentSounds");
            ExposedVariables = XmlRel.ReadItemArray<Dat54ModularSynthSoundVariable>(node, "ExposedVariables");
            ExposedVariablesCount = (ExposedVariables?.Length ?? 0);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "SynthSound", RelXml.HashString(SynthSound));
            RelXml.StringTag(sb, indent, "SynthPreset", RelXml.HashString(SynthPreset));
            RelXml.ValueTag(sb, indent, "PlaybackTimeLimit", FloatUtil.ToString(PlaybackTimeLimit));
            RelXml.ValueTag(sb, indent, "UnkInt", UnkInt.ToString());
            RelXml.ValueTag(sb, indent, "TrackCount", TrackCount.ToString());
            WriteChildSoundsXml(sb, indent, "EnvironmentSounds");
            RelXml.WriteItemArray(sb, ExposedVariables, indent, "ExposedVariables");
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(SynthSound); //0x0-0x4
            bw.Write(SynthPreset); //0x4-0x8
            bw.Write(PlaybackTimeLimit); //0x8-0xC
            bw.Write(UnkInt); //0xC-0x10
            bw.Write(TrackCount); //0x10-0x14
            for (int i = 0; i < 4; i++)
            {
                bw.Write(ChildSoundsHashes[i]);
            }
            bw.Write(ExposedVariablesCount);
            for (int i = 0; i < ExposedVariablesCount; i++)
            {
                ExposedVariables[i].Write(bw);
            }
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < 4; i++)
            {
                offsets.Add(20 + i * 4);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetSynthHashes()
        {
            return new[] { SynthSound, SynthPreset };
        }
    }
    [TC(typeof(EXP))] public class Dat54ModularSynthSoundVariable : IMetaXmlItem
    {
        public MetaHash VariableName { get; set; }
        public MetaHash ParameterName { get; set; }
        public float Value { get; set; }

        public Dat54ModularSynthSoundVariable()
        { }
        public Dat54ModularSynthSoundVariable(BinaryReader br)
        {
            VariableName = br.ReadUInt32();
            ParameterName = br.ReadUInt32();
            Value = br.ReadSingle();
        }
        public void ReadXml(XmlNode node)
        {
            VariableName = XmlRel.GetHash(Xml.GetChildInnerText(node, "VariableName"));
            ParameterName = XmlRel.GetHash(Xml.GetChildInnerText(node, "ParameterName"));
            Value = Xml.GetChildFloatAttribute(node, "Value", "value");
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "VariableName", RelXml.HashString(VariableName));
            RelXml.StringTag(sb, indent, "ParameterName", RelXml.HashString(ParameterName));
            RelXml.ValueTag(sb, indent, "Value", FloatUtil.ToString(Value));
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(VariableName);
            bw.Write(ParameterName);
            bw.Write(Value);
        }
        public override string ToString()
        {
            return VariableName.ToString() + ": " + ParameterName.ToString() + ": " + FloatUtil.ToString(Value);
        }
    }
    [TC(typeof(EXP))] public class Dat54GranularSound : Dat54Sound
    {
        public int WaveSlotIndex { get; set; } //0x0-0x4
        public Dat54GranularSoundFile Channel0 { get; set; }
        public Dat54GranularSoundFile Channel1 { get; set; }
        public Dat54GranularSoundFile Channel2 { get; set; }
        public Dat54GranularSoundFile Channel3 { get; set; }
        public Dat54GranularSoundFile Channel4 { get; set; }
        public Dat54GranularSoundFile Channel5 { get; set; }
        public Dat54GranularSoundData ChannelSettings0 { get; set; } //0x34-0x3C
        public Dat54GranularSoundData ChannelSettings1 { get; set; } //0x3C-0x44
        public Dat54GranularSoundData ChannelSettings2 { get; set; } //0x44-0x4C
        public Dat54GranularSoundData ChannelSettings3 { get; set; } //0x4C-0x54
        public Dat54GranularSoundData ChannelSettings4 { get; set; } //0x54-0x5C
        public Dat54GranularSoundData ChannelSettings5 { get; set; } //0x5C-0x64
        public float UnkFloat0 { get; set; } //0x64-0x68
        public float UnkFloat1 { get; set; } //0x68-0x6C
        public short ChannelVolume0 { get; set; } //0x6C-0x6E
        public short ChannelVolume1 { get; set; } //0x6E-0x70
        public short ChannelVolume2 { get; set; } //0x70-0x72
        public short ChannelVolume3 { get; set; } //0x72-0x74
        public short ChannelVolume4 { get; set; } //0x74-0x76
        public short ChannelVolume5 { get; set; } //0x76-0x78
        public MetaHash ParentSound { get; set; } //0x78-0x7C
        public byte GranularClockCount { get; set; } //0x7C-0x7D
        public Vector2[] GranularClock { get; set; } //0x7D-...

        public Dat54GranularSound(RelFile rel) : base(rel, Dat54SoundType.GranularSound)
        { }
        public Dat54GranularSound(RelData d, BinaryReader br) : base(d, br)
        {
            WaveSlotIndex = br.ReadInt32();

            Channel0 = new Dat54GranularSoundFile(br);
            Channel1 = new Dat54GranularSoundFile(br);
            Channel2 = new Dat54GranularSoundFile(br);
            Channel3 = new Dat54GranularSoundFile(br);
            Channel4 = new Dat54GranularSoundFile(br);
            Channel5 = new Dat54GranularSoundFile(br);

            AudioContainers = new[] {
                Channel0.ContainerName,
                Channel1.ContainerName,
                Channel2.ContainerName,
                Channel3.ContainerName,
                Channel4.ContainerName,
                Channel5.ContainerName
            };

            ChannelSettings0 = new Dat54GranularSoundData(br);
            ChannelSettings1 = new Dat54GranularSoundData(br);
            ChannelSettings2 = new Dat54GranularSoundData(br);
            ChannelSettings3 = new Dat54GranularSoundData(br);
            ChannelSettings4 = new Dat54GranularSoundData(br);
            ChannelSettings5 = new Dat54GranularSoundData(br);

            UnkFloat0 = br.ReadSingle();
            UnkFloat1 = br.ReadSingle();
            ChannelVolume0 = br.ReadInt16();
            ChannelVolume1 = br.ReadInt16();
            ChannelVolume2 = br.ReadInt16();
            ChannelVolume3 = br.ReadInt16();
            ChannelVolume4 = br.ReadInt16();
            ChannelVolume5 = br.ReadInt16();

            ParentSound = br.ReadUInt32();

            ChildSoundsHashes = new[] { ParentSound };

            GranularClockCount = br.ReadByte();
            GranularClock = new Vector2[GranularClockCount];
            for (int i = 0; i < GranularClockCount; i++)
            {
                GranularClock[i] = new Vector2(br.ReadSingle(), br.ReadSingle());
            }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            WaveSlotIndex = (byte)Xml.GetChildIntAttribute(node, "WaveSlotIndex", "value");
            Channel0 = new Dat54GranularSoundFile(node, "Channel0");
            Channel1 = new Dat54GranularSoundFile(node, "Channel1");
            Channel2 = new Dat54GranularSoundFile(node, "Channel2");
            Channel3 = new Dat54GranularSoundFile(node, "Channel3");
            Channel4 = new Dat54GranularSoundFile(node, "Channel4");
            Channel5 = new Dat54GranularSoundFile(node, "Channel5");
            ChannelSettings0 = new Dat54GranularSoundData(node, "ChannelSettings0");
            ChannelSettings1 = new Dat54GranularSoundData(node, "ChannelSettings1");
            ChannelSettings2 = new Dat54GranularSoundData(node, "ChannelSettings2");
            ChannelSettings3 = new Dat54GranularSoundData(node, "ChannelSettings3");
            ChannelSettings4 = new Dat54GranularSoundData(node, "ChannelSettings4");
            ChannelSettings5 = new Dat54GranularSoundData(node, "ChannelSettings5");
            UnkFloat0 = Xml.GetChildFloatAttribute(node, "UnkFloat0", "value");
            UnkFloat1 = Xml.GetChildFloatAttribute(node, "UnkFloat1", "value");
            ChannelVolume0 = (short)Xml.GetChildIntAttribute(node, "ChannelVolume0", "value");
            ChannelVolume1 = (short)Xml.GetChildIntAttribute(node, "ChannelVolume1", "value");
            ChannelVolume2 = (short)Xml.GetChildIntAttribute(node, "ChannelVolume2", "value");
            ChannelVolume3 = (short)Xml.GetChildIntAttribute(node, "ChannelVolume3", "value");
            ChannelVolume4 = (short)Xml.GetChildIntAttribute(node, "ChannelVolume4", "value");
            ChannelVolume5 = (short)Xml.GetChildIntAttribute(node, "ChannelVolume5", "value");
            ParentSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ParentSound"));
            GranularClock = Xml.GetChildRawVector2Array(node, "GranularClock");
            GranularClockCount = (byte)GranularClock?.Length;
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "WaveSlotIndex", WaveSlotIndex.ToString());
            Channel0.WriteXml(sb, indent, "Channel0");
            Channel1.WriteXml(sb, indent, "Channel1");
            Channel2.WriteXml(sb, indent, "Channel2");
            Channel3.WriteXml(sb, indent, "Channel3");
            Channel4.WriteXml(sb, indent, "Channel4");
            Channel5.WriteXml(sb, indent, "Channel5");
            ChannelSettings0.WriteXml(sb, indent, "ChannelSettings0");
            ChannelSettings1.WriteXml(sb, indent, "ChannelSettings1");
            ChannelSettings2.WriteXml(sb, indent, "ChannelSettings2");
            ChannelSettings3.WriteXml(sb, indent, "ChannelSettings3");
            ChannelSettings4.WriteXml(sb, indent, "ChannelSettings4");
            ChannelSettings5.WriteXml(sb, indent, "ChannelSettings5");
            RelXml.ValueTag(sb, indent, "UnkFloat0", FloatUtil.ToString(UnkFloat0));
            RelXml.ValueTag(sb, indent, "UnkFloat1", FloatUtil.ToString(UnkFloat1));
            RelXml.ValueTag(sb, indent, "ChannelVolume0", ChannelVolume0.ToString());
            RelXml.ValueTag(sb, indent, "ChannelVolume1", ChannelVolume1.ToString());
            RelXml.ValueTag(sb, indent, "ChannelVolume2", ChannelVolume2.ToString());
            RelXml.ValueTag(sb, indent, "ChannelVolume3", ChannelVolume3.ToString());
            RelXml.ValueTag(sb, indent, "ChannelVolume4", ChannelVolume4.ToString());
            RelXml.ValueTag(sb, indent, "ChannelVolume5", ChannelVolume5.ToString());
            RelXml.StringTag(sb, indent, "ParentSound", RelXml.HashString(ParentSound));
            RelXml.WriteRawArray(sb, GranularClock, indent, "GranularClock", "", RelXml.FormatVector2, 1);
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);

            bw.Write(WaveSlotIndex);

            Channel0.Write(bw);
            Channel1.Write(bw);
            Channel2.Write(bw);
            Channel3.Write(bw);
            Channel4.Write(bw);
            Channel5.Write(bw);

            ChannelSettings0.Write(bw);
            ChannelSettings1.Write(bw);
            ChannelSettings2.Write(bw);
            ChannelSettings3.Write(bw);
            ChannelSettings4.Write(bw);
            ChannelSettings5.Write(bw);

            bw.Write(UnkFloat0);
            bw.Write(UnkFloat1);
            bw.Write(ChannelVolume0);
            bw.Write(ChannelVolume1);
            bw.Write(ChannelVolume2);
            bw.Write(ChannelVolume3);
            bw.Write(ChannelVolume4);
            bw.Write(ChannelVolume5);

            bw.Write(ParentSound);

            bw.Write(GranularClockCount);
            for (int i = 0; i < GranularClockCount; i++)
            {
                bw.Write(GranularClock[i].X);
                bw.Write(GranularClock[i].Y);
            }
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 120 };
        }
        public override uint[] GetPackTableOffsets()
        {
            return new uint[] { 4, 12, 20, 28, 36, 44 };
        }
    }
    [TC(typeof(EXP))] public class Dat54GranularSoundFile
    {
        public MetaHash ContainerName { get; set; } //0x0-0x4
        public MetaHash FileName { get; set; } //0x4-0x8

        public Dat54GranularSoundFile(XmlNode node, string varName)
        {
            ReadXml(node, varName);
        }
        public Dat54GranularSoundFile(BinaryReader br)
        {
            ContainerName = br.ReadUInt32();
            FileName = br.ReadUInt32();
        }
        public void ReadXml(XmlNode node, string varName)
        {
            var cnode = node.SelectSingleNode(varName);
            ContainerName = XmlRel.GetHash(Xml.GetChildInnerText(cnode, "ContainerName"));
            FileName = XmlRel.GetHash(Xml.GetChildInnerText(cnode, "FileName"));
        }
        public void WriteXml(StringBuilder sb, int indent, string varName)
        {
            var cind = indent + 1;
            RelXml.OpenTag(sb, indent, varName);
            RelXml.StringTag(sb, cind, "ContainerName", RelXml.HashString(ContainerName));
            RelXml.StringTag(sb, cind, "FileName", RelXml.HashString(FileName));
            RelXml.CloseTag(sb, indent, varName);
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(ContainerName);
            bw.Write(FileName);
        }
        public override string ToString()
        {
            return ContainerName.ToString() + ": " + FileName.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat54GranularSoundData
    {
        public byte UnkFlags0 { get; set; } //0x0-0x1
        public byte UnkFlags1 { get; set; } //0x1-0x2
        public byte UnkByte0 { get; set; } //0x2-0x3
        public byte UnkByte1 { get; set; } //0x3-0x4
        public float UnkFloat { get; set; } //0x4-0x8

        public Dat54GranularSoundData(XmlNode node, string varName)
        {
            ReadXml(node, varName);
        }
        public Dat54GranularSoundData(BinaryReader br)
        {
            UnkFlags0 = br.ReadByte();
            UnkFlags1 = br.ReadByte();
            UnkByte0 = br.ReadByte();
            UnkByte1 = br.ReadByte();
            UnkFloat = br.ReadSingle();
        }
        public void ReadXml(XmlNode node, string varName)
        {
            var cnode = node.SelectSingleNode(varName);
            UnkFlags0 = (byte)Xml.GetChildIntAttribute(cnode, "UnkFlags0", "value");
            UnkFlags1 = (byte)Xml.GetChildIntAttribute(cnode, "UnkFlags1", "value");
            UnkByte0 = (byte)Xml.GetChildIntAttribute(cnode, "UnkByte0", "value");
            UnkByte1 = (byte)Xml.GetChildIntAttribute(cnode, "UnkByte1", "value");
            UnkFloat = Xml.GetChildFloatAttribute(cnode, "UnkFloat", "value");
        }
        public void WriteXml(StringBuilder sb, int indent, string varName)
        {
            var cind = indent + 1;
            RelXml.OpenTag(sb, indent, varName);
            RelXml.ValueTag(sb, cind, "UnkFlags0", UnkFlags0.ToString());
            RelXml.ValueTag(sb, cind, "UnkFlags1", UnkFlags1.ToString());
            RelXml.ValueTag(sb, cind, "UnkByte0", UnkByte0.ToString());
            RelXml.ValueTag(sb, cind, "UnkByte1", UnkByte1.ToString());
            RelXml.ValueTag(sb, cind, "UnkFloat", FloatUtil.ToString(UnkFloat));
            RelXml.CloseTag(sb, indent, varName);
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(UnkFlags0);
            bw.Write(UnkFlags1);
            bw.Write(UnkByte0);
            bw.Write(UnkByte1);
            bw.Write(UnkFloat);
        }
        public override string ToString()
        {
            return UnkFlags0.ToString() + ": " + UnkFlags1.ToString() + ": " + UnkByte0.ToString() + ": " + UnkByte1.ToString() + ": " + FloatUtil.ToString(UnkFloat);
        }
    }
    [TC(typeof(EXP))] public class Dat54DirectionalSound : Dat54Sound
    {
        public MetaHash ChildSound { get; set; }
        public float InnerAngle { get; set; } //0x4-0x8
        public float OuterAngle { get; set; } //0x8-0xC
        public float RearAttenuation { get; set; } //0xC-0x10
        public float YawAngle { get; set; } //0x10-0x14
        public float PitchAngle { get; set; } //0x14-0x18

        public Dat54DirectionalSound(RelFile rel) : base(rel, Dat54SoundType.DirectionalSound)
        { }
        public Dat54DirectionalSound(RelData d, BinaryReader br) : base(d, br)
        {
            ChildSound = br.ReadUInt32();
            ChildSoundsHashes = new[] { ChildSound };
            InnerAngle = br.ReadSingle();
            OuterAngle = br.ReadSingle();
            RearAttenuation = br.ReadSingle();
            YawAngle = br.ReadSingle();
            PitchAngle = br.ReadSingle();
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
            InnerAngle = Xml.GetChildFloatAttribute(node, "InnerAngle", "value");
            OuterAngle = Xml.GetChildFloatAttribute(node, "OuterAngle", "value");
            RearAttenuation = Xml.GetChildFloatAttribute(node, "RearAttenuation", "value");
            YawAngle = Xml.GetChildFloatAttribute(node, "YawAngle", "value");
            PitchAngle = Xml.GetChildFloatAttribute(node, "PitchAngle", "value");
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
            RelXml.ValueTag(sb, indent, "InnerAngle", FloatUtil.ToString(InnerAngle));
            RelXml.ValueTag(sb, indent, "OuterAngle", FloatUtil.ToString(OuterAngle));
            RelXml.ValueTag(sb, indent, "RearAttenuation", FloatUtil.ToString(RearAttenuation));
            RelXml.ValueTag(sb, indent, "YawAngle", FloatUtil.ToString(YawAngle));
            RelXml.ValueTag(sb, indent, "PitchAngle", FloatUtil.ToString(PitchAngle));
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(ChildSound);
            bw.Write(InnerAngle);
            bw.Write(OuterAngle);
            bw.Write(RearAttenuation);
            bw.Write(YawAngle);
            bw.Write(PitchAngle);
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0 };
        }
    }
    [TC(typeof(EXP))] public class Dat54KineticSound : Dat54Sound
    {
        public MetaHash ChildSound { get; set; }
        public float Mass { get; set; } //according to GDC presentation
        public float YawAngle { get; set; } //according to GDC presentation
        public float PitchAngle { get; set; } //according to GDC presentation

        public Dat54KineticSound(RelFile rel) : base(rel, Dat54SoundType.KineticSound)
        { }
        public Dat54KineticSound(RelData d, BinaryReader br) : base(d, br)
        {
            ChildSound = br.ReadUInt32();
            ChildSoundsHashes = new[] { ChildSound };
            Mass = br.ReadSingle();
            YawAngle = br.ReadSingle();
            PitchAngle = br.ReadSingle();
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
            Mass = Xml.GetChildFloatAttribute(node, "Mass", "value");
            YawAngle = Xml.GetChildFloatAttribute(node, "YawAngle", "value");
            PitchAngle = Xml.GetChildFloatAttribute(node, "PitchAngle", "value");
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
            RelXml.ValueTag(sb, indent, "Mass", FloatUtil.ToString(Mass));
            RelXml.ValueTag(sb, indent, "YawAngle", FloatUtil.ToString(YawAngle));
            RelXml.ValueTag(sb, indent, "PitchAngle", FloatUtil.ToString(PitchAngle));
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(ChildSound);
            bw.Write(Mass);
            bw.Write(YawAngle);
            bw.Write(PitchAngle);
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0 };
        }
    }
    [TC(typeof(EXP))] public class Dat54SwitchSound : Dat54Sound
    {
        public MetaHash Variable { get; set; } //0x0-0x4

        public Dat54SwitchSound(RelFile rel) : base(rel, Dat54SoundType.SwitchSound)
        { }
        public Dat54SwitchSound(RelData d, BinaryReader br) : base(d, br)
        {
            Variable = br.ReadUInt32();

            ReadChildSoundsHashes(br);
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Variable = XmlRel.GetHash(Xml.GetChildInnerText(node, "Variable"));
            ReadChildSoundsXml(node);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "Variable", RelXml.HashString(Variable));
            WriteChildSoundsXml(sb, indent);
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(Variable);
            WriteChildSoundsHashes(bw);
        }
        public override uint[] GetHashTableOffsets()
        {
            return GetChildSoundsHashTableOffsets(4);
        }
    }
    [TC(typeof(EXP))] public class Dat54VariableCurveSound : Dat54Sound
    {
        public MetaHash ChildSound { get; set; }
        public MetaHash InputVariable { get; set; } //0x4-0x8
        public MetaHash OutputVariable { get; set; } //0x8-0xC
        public MetaHash Curve { get; set; } //0xC-0x10

        public Dat54VariableCurveSound(RelFile rel) : base(rel, Dat54SoundType.VariableCurveSound)
        { }
        public Dat54VariableCurveSound(RelData d, BinaryReader br) : base(d, br)
        {
            ChildSound = br.ReadUInt32();
            ChildSoundsHashes = new[] { ChildSound };
            InputVariable = br.ReadUInt32();
            OutputVariable = br.ReadUInt32();
            Curve = br.ReadUInt32();
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
            InputVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "InputVariable"));
            OutputVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "OutputVariable"));
            Curve = XmlRel.GetHash(Xml.GetChildInnerText(node, "Curve"));
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
            RelXml.StringTag(sb, indent, "InputVariable", RelXml.HashString(InputVariable));
            RelXml.StringTag(sb, indent, "OutputVariable", RelXml.HashString(OutputVariable));
            RelXml.StringTag(sb, indent, "Curve", RelXml.HashString(Curve));
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(ChildSound);
            bw.Write(InputVariable);
            bw.Write(OutputVariable);
            bw.Write(Curve);
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0 };
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { Curve };
        }
    }
    [TC(typeof(EXP))] public class Dat54VariablePrintValueSound : Dat54Sound
    {
        public MetaHash Variable { get; set; } //0x0-0x4
        public string Value { get; set; }

        public Dat54VariablePrintValueSound(RelFile rel) : base(rel, Dat54SoundType.VariablePrintValueSound)
        { }
        public Dat54VariablePrintValueSound(RelData d, BinaryReader br) : base(d, br)
        {
            Variable = br.ReadUInt32();
            Value = br.ReadString();
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Variable = XmlRel.GetHash(Xml.GetChildInnerText(node, "Variable"));
            Value = Xml.GetChildInnerText(node, "Value");
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "Variable", RelXml.HashString(Variable));
            RelXml.StringTag(sb, indent, "Value", Value);
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(Variable);
            bw.Write(Value);
        }
    }
    [TC(typeof(EXP))] public class Dat54VariableBlockSound : Dat54Sound
    {
        public MetaHash ChildSound { get; set; }
        public byte VariableCount { get; set; }
        public Dat54VariableData[] Variables { get; set; }

        public Dat54VariableBlockSound(RelFile rel) : base(rel, Dat54SoundType.VariableBlockSound)
        { }
        public Dat54VariableBlockSound(RelData d, BinaryReader br) : base(d, br)
        {
            ChildSound = br.ReadUInt32();
            ChildSoundsHashes = new[] { ChildSound };
            VariableCount = br.ReadByte();
            Variables = new Dat54VariableData[VariableCount];
            for (int i = 0; i < VariableCount; i++)
            {
                Variables[i] = new Dat54VariableData(br);
            }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
            Variables = XmlRel.ReadItemArray<Dat54VariableData>(node, "Variables");
            VariableCount = (byte)(Variables?.Length ?? 0);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
            RelXml.WriteItemArray(sb, Variables, indent, "Variables");
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(ChildSound);
            bw.Write(VariableCount);
            for (int i = 0; i < VariableCount; i++)
            {
                Variables[i].Write(bw);
            }
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0 };
        }
    }
    [TC(typeof(EXP))] public class Dat54VariableData : IMetaXmlItem
    {
        public MetaHash Name { get; set; }
        public float Value { get; set; } //the value this variable is set to.
        public float ValueVariance { get; set; } //variance of the value
        public byte VariableType { get; set; } //type of variable... sound, code, constant

        public Dat54VariableData()
        { }
        public Dat54VariableData(BinaryReader br)
        {
            Name = br.ReadUInt32();
            Value = br.ReadSingle();
            ValueVariance = br.ReadSingle();
            VariableType = br.ReadByte();
        }
        public void ReadXml(XmlNode node)
        {
            Name = XmlRel.GetHash(Xml.GetChildInnerText(node, "Name"));
            Value = Xml.GetChildFloatAttribute(node, "Value", "value");
            ValueVariance = Xml.GetChildFloatAttribute(node, "ValueVariance", "value");
            VariableType = (byte)Xml.GetChildIntAttribute(node, "VariableType", "value");
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Name", RelXml.HashString(Name));
            RelXml.ValueTag(sb, indent, "Value", FloatUtil.ToString(Value));
            RelXml.ValueTag(sb, indent, "ValueVariance", FloatUtil.ToString(ValueVariance));
            RelXml.ValueTag(sb, indent, "VariableType", VariableType.ToString());
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Name);
            bw.Write(Value);
            bw.Write(ValueVariance);
            bw.Write(VariableType);
        }
        public override string ToString()
        {
            return Name + ": " + FloatUtil.ToString(Value) + ": " + FloatUtil.ToString(ValueVariance) + ": " + VariableType.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat54IfSound : Dat54Sound
    {
        public MetaHash TrueSound { get; set; } //sound played if the condition is true
        public MetaHash FalseSound { get; set; } //sound played if the condition is false/invalid
        public MetaHash ConditionVariable { get; set; } //the parameter used to make the choise
        public byte ConditionType { get; set; } //equal to, less than, greater than, etc...
        public float ConditionValue { get; set; } //the value its comparing the parameter to.
        public MetaHash IfParameterHash1 { get; set; } //?

        public Dat54IfSound(RelFile rel) : base(rel, Dat54SoundType.IfSound)
        { }
        public Dat54IfSound(RelData d, BinaryReader br) : base(d, br)
        {
            TrueSound = br.ReadUInt32();
            FalseSound = br.ReadUInt32();
            ChildSoundsHashes = new[] { TrueSound, FalseSound };
            ConditionVariable = br.ReadUInt32();
            ConditionType = br.ReadByte();
            ConditionValue = br.ReadSingle();
            IfParameterHash1 = br.ReadUInt32();
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            TrueSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "TrueSound"));
            FalseSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "FalseSound"));
            ConditionVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "ConditionVariable"));
            ConditionType = (byte)Xml.GetChildIntAttribute(node, "ConditionType", "value");
            ConditionValue = Xml.GetChildFloatAttribute(node, "ConditionValue", "value");
            IfParameterHash1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "IfParameterHash1"));
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "TrueSound", RelXml.HashString(TrueSound));
            RelXml.StringTag(sb, indent, "FalseSound", RelXml.HashString(FalseSound));
            RelXml.StringTag(sb, indent, "ConditionVariable", RelXml.HashString(ConditionVariable));
            RelXml.ValueTag(sb, indent, "ConditionType", ConditionType.ToString());
            RelXml.ValueTag(sb, indent, "ConditionValue", FloatUtil.ToString(ConditionValue));
            RelXml.StringTag(sb, indent, "IfParameterHash1", RelXml.HashString(IfParameterHash1));
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(TrueSound);
            bw.Write(FalseSound);
            bw.Write(ConditionVariable);
            bw.Write(ConditionType);
            bw.Write(ConditionValue);
            bw.Write(IfParameterHash1);
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0, 4 };
        }
    }
    [TC(typeof(EXP))] public class Dat54MathOperationSound : Dat54Sound
    {
        public MetaHash ChildSound { get; set; }
        public byte OperationsCount { get; set; }
        public Dat54MathOperationSoundData[] Operations { get; set; }

        public Dat54MathOperationSound(RelFile rel) : base(rel, Dat54SoundType.MathOperationSound)
        { }
        public Dat54MathOperationSound(RelData d, BinaryReader br) : base(d, br)
        {
            ChildSound = br.ReadUInt32();
            ChildSoundsHashes = new[] { ChildSound };
            OperationsCount = br.ReadByte();
            Operations = new Dat54MathOperationSoundData[OperationsCount];
            for (int i = 0; i < OperationsCount; i++)
            {
                Operations[i] = new Dat54MathOperationSoundData(br);
            }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
            Operations = XmlRel.ReadItemArray<Dat54MathOperationSoundData>(node, "Operations");
            OperationsCount = (byte)(Operations?.Length ?? 0);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
            RelXml.WriteItemArray(sb, Operations, indent, "Operations");
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(ChildSound);
            bw.Write(OperationsCount);
            for (int i = 0; i < OperationsCount; i++)
            {
                Operations[i].Write(bw);
            }
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0 };
        }
    }
    [TC(typeof(EXP))] public class Dat54MathOperationSoundData : IMetaXmlItem
    {
        public byte OperationType { get; set; } //0x0-0x1
        public float InputImmediate1 { get; set; } //0x1-0x5
        public MetaHash InputParameter1 { get; set; } //0x5-0x9
        public float InputImmediate2 { get; set; } //0x9-0xD
        public MetaHash InputParameter2 { get; set; } //0xD-0x11
        public float InputImmediate3 { get; set; } //0x11-0x15
        public MetaHash InputParameter3 { get; set; } //0x15-0x19
        public MetaHash OutputParameter { get; set; } //0x19-0x1D

        public Dat54MathOperationSoundData()
        { }
        public Dat54MathOperationSoundData(BinaryReader br)
        {
            OperationType = br.ReadByte();
            InputImmediate1 = br.ReadSingle();
            InputParameter1 = br.ReadUInt32();
            InputImmediate2 = br.ReadSingle();
            InputParameter2 = br.ReadUInt32();
            InputImmediate3 = br.ReadSingle();
            InputParameter3 = br.ReadUInt32();
            OutputParameter = br.ReadUInt32();
        }
        public void ReadXml(XmlNode node)
        {
            OperationType = (byte)Xml.GetChildIntAttribute(node, "OperationType", "value");
            InputImmediate1 = Xml.GetChildFloatAttribute(node, "InputImmediate1", "value");
            InputParameter1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "InputParameter1"));
            InputImmediate2 = Xml.GetChildFloatAttribute(node, "InputImmediate2", "value");
            InputParameter2 = XmlRel.GetHash(Xml.GetChildInnerText(node, "InputParameter2"));
            InputImmediate3 = Xml.GetChildFloatAttribute(node, "InputImmediate3", "value");
            InputParameter3 = XmlRel.GetHash(Xml.GetChildInnerText(node, "InputParameter3"));
            OutputParameter = XmlRel.GetHash(Xml.GetChildInnerText(node, "OutputParameter"));
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "OperationType", OperationType.ToString());
            RelXml.ValueTag(sb, indent, "InputImmediate1", FloatUtil.ToString(InputImmediate1));
            RelXml.StringTag(sb, indent, "InputParameter1", RelXml.HashString(InputParameter1));
            RelXml.ValueTag(sb, indent, "InputImmediate2", FloatUtil.ToString(InputImmediate2));
            RelXml.StringTag(sb, indent, "InputParameter2", RelXml.HashString(InputParameter2));
            RelXml.ValueTag(sb, indent, "InputImmediate3", FloatUtil.ToString(InputImmediate3));
            RelXml.StringTag(sb, indent, "InputParameter3", RelXml.HashString(InputParameter3));
            RelXml.StringTag(sb, indent, "OutputParameter", RelXml.HashString(OutputParameter));
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(OperationType);
            bw.Write(InputImmediate1);
            bw.Write(InputParameter1);
            bw.Write(InputImmediate2);
            bw.Write(InputParameter2);
            bw.Write(InputImmediate3);
            bw.Write(InputParameter3);
            bw.Write(OutputParameter);
        }
        public override string ToString()
        {
            return InputParameter3.ToString() + ", " + OutputParameter.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat54ParameterTransformSound : Dat54Sound
    {
        public MetaHash ChildSound { get; set; }
        public int ParameterTransformsCount { get; set; }
        public Dat54ParameterTransformSoundData[] ParameterTransforms { get; set; }

        public Dat54ParameterTransformSound(RelFile rel) : base(rel, Dat54SoundType.ParameterTransformSound)
        { }
        public Dat54ParameterTransformSound(RelData d, BinaryReader br) : base(d, br)
        {
            ChildSound = br.ReadUInt32();
            ChildSoundsHashes = new[] { ChildSound };
            ParameterTransformsCount = br.ReadInt32(); //0x4-0x8
            ParameterTransforms = new Dat54ParameterTransformSoundData[ParameterTransformsCount];
            for (int i = 0; i < ParameterTransformsCount; i++)
            {
                ParameterTransforms[i] = new Dat54ParameterTransformSoundData(br);
            }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
            ParameterTransforms = XmlRel.ReadItemArray<Dat54ParameterTransformSoundData>(node, "ParameterTransforms");
            ParameterTransformsCount = (ParameterTransforms?.Length ?? 0);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
            RelXml.WriteItemArray(sb, ParameterTransforms, indent, "ParameterTransforms");
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(ChildSound);
            bw.Write(ParameterTransformsCount); //0x4-0x8
            for (int i = 0; i < ParameterTransformsCount; i++)
            {
                ParameterTransforms[i].Write(bw);
            }
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0 };
        }
    }
    [TC(typeof(EXP))] public class Dat54ParameterTransformSoundData : IMetaXmlItem
    {
        public MetaHash InputParameter { get; set; } //0x0-0x4
        public float InputRangeMin { get; set; } //0x4-0x8
        public float InputRangeMax { get; set; } //0x8-0xC
        public int TransformsCount { get; set; }
        public Dat54ParameterTransformSoundData2[] Transforms { get; set; } //0x10..

        public Dat54ParameterTransformSoundData()
        { }
        public Dat54ParameterTransformSoundData(BinaryReader br)
        {
            InputParameter = br.ReadUInt32();
            InputRangeMin = br.ReadSingle();
            InputRangeMax = br.ReadSingle();
            TransformsCount = br.ReadInt32();
            Transforms = new Dat54ParameterTransformSoundData2[TransformsCount];
            for (int i = 0; i < TransformsCount; i++)
            {
                Transforms[i] = new Dat54ParameterTransformSoundData2(br);
            }
        }
        public void ReadXml(XmlNode node)
        {
            InputParameter = XmlRel.GetHash(Xml.GetChildInnerText(node, "InputParameter"));
            InputRangeMin = Xml.GetChildFloatAttribute(node, "InputRangeMin", "value");
            InputRangeMax = Xml.GetChildFloatAttribute(node, "InputRangeMax", "value");
            Transforms = XmlRel.ReadItemArray<Dat54ParameterTransformSoundData2>(node, "Transforms");
            TransformsCount = Transforms?.Length ?? 0;
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "InputParameter", RelXml.HashString(InputParameter));
            RelXml.ValueTag(sb, indent, "InputRangeMin", FloatUtil.ToString(InputRangeMin));
            RelXml.ValueTag(sb, indent, "InputRangeMax", FloatUtil.ToString(InputRangeMax));
            RelXml.WriteItemArray(sb, Transforms, indent, "Transforms");
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(InputParameter);
            bw.Write(InputRangeMin);
            bw.Write(InputRangeMax);
            bw.Write(TransformsCount);
            for (int i = 0; i < TransformsCount; i++)
            {
                Transforms[i].Write(bw);
            }
        }
        public override string ToString()
        {
            return InputParameter.ToString() + ", " + TransformsCount.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat54ParameterTransformSoundData2 : IMetaXmlItem
    {
        public float SmoothRate { get; set; } //0x0-0x4
        public int TransformType { get; set; } //0x4 //type of transform; volume, pitch, etc
        public MetaHash TransformTypeParameter { get; set; } //0x8-0xC //
        public float OutputRangeMin { get; set; } //0xC //output range min, multiplies the range covered by the vectors
        public float OutputRangeMax { get; set; } //0x10-0x14 //output range max, multiplies the range covered by the vectors
        public int VectorCount { get; set; }
        public Vector2[] Vectors { get; set; } //0x18-... //vector graph

        public Dat54ParameterTransformSoundData2()
        { }
        public Dat54ParameterTransformSoundData2(BinaryReader br)
        {
            SmoothRate = br.ReadSingle();
            TransformType = br.ReadInt32();
            TransformTypeParameter = br.ReadUInt32();
            OutputRangeMin = br.ReadSingle();
            OutputRangeMax = br.ReadSingle();
            VectorCount = br.ReadInt32();
            Vectors = new Vector2[VectorCount];
            for (int i = 0; i < VectorCount; i++)
            {
                Vectors[i] = new Vector2(br.ReadSingle(), br.ReadSingle());
            }
        }
        public void ReadXml(XmlNode node)
        {
            SmoothRate = Xml.GetChildFloatAttribute(node, "SmoothRate", "value");
            TransformType = Xml.GetChildIntAttribute(node, "TransformType", "value");
            TransformTypeParameter = XmlRel.GetHash(Xml.GetChildInnerText(node, "TransformTypeParameter"));
            OutputRangeMin = Xml.GetChildFloatAttribute(node, "OutputRangeMin", "value");
            OutputRangeMax = Xml.GetChildFloatAttribute(node, "OutputRangeMax", "value");
            Vectors = Xml.GetChildRawVector2Array(node, "Vectors");
            VectorCount = Vectors?.Length ?? 0;
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "SmoothRate", FloatUtil.ToString(SmoothRate));
            RelXml.ValueTag(sb, indent, "TransformType", TransformType.ToString());
            RelXml.StringTag(sb, indent, "TransformTypeParameter", RelXml.HashString(TransformTypeParameter));
            RelXml.ValueTag(sb, indent, "OutputRangeMin", FloatUtil.ToString(OutputRangeMin));
            RelXml.ValueTag(sb, indent, "OutputRangeMax", FloatUtil.ToString(OutputRangeMax));
            RelXml.WriteRawArray(sb, Vectors, indent, "Vectors", "", RelXml.FormatVector2, 1);
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(SmoothRate);
            bw.Write(TransformType);
            bw.Write(TransformTypeParameter);
            bw.Write(OutputRangeMin);
            bw.Write(OutputRangeMax);
            bw.Write(VectorCount);
            for (int i = 0; i < VectorCount; i++)
            {
                bw.Write(Vectors[i].X);
                bw.Write(Vectors[i].Y);
            }
        }
        public override string ToString()
        {
            return TransformTypeParameter.ToString() + ", " + VectorCount.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat54FluctuatorSound : Dat54Sound
    {
        public MetaHash ChildSound { get; set; }
        public int FluctuatorsCount { get; set; }
        public Dat54FluctuatorSoundData[] Fluctuators { get; set; }

        public Dat54FluctuatorSound(RelFile rel) : base(rel, Dat54SoundType.FluctuatorSound)
        { }
        public Dat54FluctuatorSound(RelData d, BinaryReader br) : base(d, br)
        {
            ChildSound = br.ReadUInt32();
            ChildSoundsHashes = new[] { ChildSound };
            FluctuatorsCount = br.ReadInt32(); //0x4-0x8
            Fluctuators = new Dat54FluctuatorSoundData[FluctuatorsCount];
            for (int i = 0; i < FluctuatorsCount; i++)
            {
                Fluctuators[i] = new Dat54FluctuatorSoundData(br);
            }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
            Fluctuators = XmlRel.ReadItemArray<Dat54FluctuatorSoundData>(node, "Fluctuators");
            FluctuatorsCount = (Fluctuators?.Length ?? 0);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
            RelXml.WriteItemArray(sb, Fluctuators, indent, "Fluctuators");
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(ChildSound);
            bw.Write(FluctuatorsCount); //0x4-0x8
            for (int i = 0; i < FluctuatorsCount; i++)
            {
                Fluctuators[i].Write(bw);
            }
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0 };
        }
    }
    [TC(typeof(EXP))] public class Dat54FluctuatorSoundData : IMetaXmlItem
    {
        public byte FluctuatorType { get; set; } //0x0-0x1 //type of fluctuator; probability-based, time-based
        public byte UnkByte1 { get; set; } //0x1-0x2
        public MetaHash ParameterHash { get; set; } //0x2-0x6
        public float UnkFloat00 { get; set; } //0x6-0xA
        public float UnkFloat01 { get; set; } //0xA-0xE
        public float UnkFloat02 { get; set; } //0xE-0x12
        public float UnkFloat03 { get; set; } //0x12-0x16
        public float UnkFloat04 { get; set; } //0x16-0x1A
        public float UnkFloat05 { get; set; } //0x1A-0x1E
        public float UnkFloat06 { get; set; } //0x1E-0x22
        public float UnkFloat07 { get; set; } //0x22-0x26
        public float UnkFloat08 { get; set; } //0x26-0x2A
        public float UnkFloat09 { get; set; } //0x2A-0x2E
        public float UnkFloat10 { get; set; } //0x2E-0x32

        public Dat54FluctuatorSoundData()
        { }
        public Dat54FluctuatorSoundData(BinaryReader br)
        {
            FluctuatorType = br.ReadByte();
            UnkByte1 = br.ReadByte();
            ParameterHash = br.ReadUInt32();
            UnkFloat00 = br.ReadSingle();
            UnkFloat01 = br.ReadSingle();
            UnkFloat02 = br.ReadSingle();
            UnkFloat03 = br.ReadSingle();
            UnkFloat04 = br.ReadSingle();
            UnkFloat05 = br.ReadSingle();
            UnkFloat06 = br.ReadSingle();
            UnkFloat07 = br.ReadSingle();
            UnkFloat08 = br.ReadSingle();
            UnkFloat09 = br.ReadSingle();
            UnkFloat10 = br.ReadSingle();
        }
        public void ReadXml(XmlNode node)
        {
            FluctuatorType = (byte)Xml.GetChildIntAttribute(node, "FluctuatorType", "value");
            UnkByte1 = (byte)Xml.GetChildIntAttribute(node, "UnkByte1", "value");
            ParameterHash = XmlRel.GetHash(Xml.GetChildInnerText(node, "ParameterHash"));
            UnkFloat00 = Xml.GetChildFloatAttribute(node, "UnkFloat00", "value");
            UnkFloat01 = Xml.GetChildFloatAttribute(node, "UnkFloat01", "value");
            UnkFloat02 = Xml.GetChildFloatAttribute(node, "UnkFloat02", "value");
            UnkFloat03 = Xml.GetChildFloatAttribute(node, "UnkFloat03", "value");
            UnkFloat04 = Xml.GetChildFloatAttribute(node, "UnkFloat04", "value");
            UnkFloat05 = Xml.GetChildFloatAttribute(node, "UnkFloat05", "value");
            UnkFloat06 = Xml.GetChildFloatAttribute(node, "UnkFloat06", "value");
            UnkFloat07 = Xml.GetChildFloatAttribute(node, "UnkFloat07", "value");
            UnkFloat08 = Xml.GetChildFloatAttribute(node, "UnkFloat08", "value");
            UnkFloat09 = Xml.GetChildFloatAttribute(node, "UnkFloat09", "value");
            UnkFloat10 = Xml.GetChildFloatAttribute(node, "UnkFloat10", "value");
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "FluctuatorType", FluctuatorType.ToString());
            RelXml.ValueTag(sb, indent, "UnkByte1", UnkByte1.ToString());
            RelXml.StringTag(sb, indent, "ParameterHash", RelXml.HashString(ParameterHash));
            RelXml.ValueTag(sb, indent, "UnkFloat00", FloatUtil.ToString(UnkFloat00));
            RelXml.ValueTag(sb, indent, "UnkFloat01", FloatUtil.ToString(UnkFloat01));
            RelXml.ValueTag(sb, indent, "UnkFloat02", FloatUtil.ToString(UnkFloat02));
            RelXml.ValueTag(sb, indent, "UnkFloat03", FloatUtil.ToString(UnkFloat03));
            RelXml.ValueTag(sb, indent, "UnkFloat04", FloatUtil.ToString(UnkFloat04));
            RelXml.ValueTag(sb, indent, "UnkFloat05", FloatUtil.ToString(UnkFloat05));
            RelXml.ValueTag(sb, indent, "UnkFloat06", FloatUtil.ToString(UnkFloat06));
            RelXml.ValueTag(sb, indent, "UnkFloat07", FloatUtil.ToString(UnkFloat07));
            RelXml.ValueTag(sb, indent, "UnkFloat08", FloatUtil.ToString(UnkFloat08));
            RelXml.ValueTag(sb, indent, "UnkFloat09", FloatUtil.ToString(UnkFloat09));
            RelXml.ValueTag(sb, indent, "UnkFloat10", FloatUtil.ToString(UnkFloat10));
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(FluctuatorType);
            bw.Write(UnkByte1);
            bw.Write(ParameterHash);
            bw.Write(UnkFloat00);
            bw.Write(UnkFloat01);
            bw.Write(UnkFloat02);
            bw.Write(UnkFloat03);
            bw.Write(UnkFloat04);
            bw.Write(UnkFloat05);
            bw.Write(UnkFloat06);
            bw.Write(UnkFloat07);
            bw.Write(UnkFloat08);
            bw.Write(UnkFloat09);
            bw.Write(UnkFloat10);
        }
        public override string ToString()
        {
            return ParameterHash.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat54AutomationSound : Dat54Sound
    {
        public MetaHash FallBackSound { get; set; }  //fallback sound
        public float PlaybackRate { get; set; } //0x4-0x8 //rate at which the midi is played back, 1.0 default
        public float PlaybackRateVariance { get; set; } //0x8-0xC //variance of the playback rate
        public MetaHash PlaybackRateVariable { get; set; } //0xC-0x10 //parameter override for playback rate
        public MetaHash NoteMap { get; set; } //mapping note sounds onto the midi
        public MetaHash ContainerName { get; set; } //0x14-0x18 // file path
        public MetaHash FileName { get; set; } //0x18-0x1C // .mid file name
        public int VariableOutputsCount { get; set; } // array data count 0x1C-0x20
        public Dat54AutomationSoundVariableOutput[] VariableOutputs { get; set; } //0x20-

        public Dat54AutomationSound(RelFile rel) : base(rel, Dat54SoundType.AutomationSound)
        { }
        public Dat54AutomationSound(RelData d, BinaryReader br) : base(d, br)
        {
            FallBackSound = br.ReadUInt32();
            PlaybackRate = br.ReadSingle();
            PlaybackRateVariance = br.ReadSingle();
            PlaybackRateVariable = br.ReadUInt32();
            NoteMap = br.ReadUInt32();
            ChildSoundsHashes = new[] { FallBackSound, NoteMap };
            ContainerName = br.ReadUInt32();
            FileName = br.ReadUInt32();
            VariableOutputsCount = br.ReadInt32();
            VariableOutputs = new Dat54AutomationSoundVariableOutput[VariableOutputsCount];
            for (int i = 0; i < VariableOutputsCount; i++)
            {
                VariableOutputs[i] = new Dat54AutomationSoundVariableOutput(br);
            }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            FallBackSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "FallBackSound"));
            PlaybackRate = Xml.GetChildFloatAttribute(node, "PlaybackRate", "value");
            PlaybackRateVariance = Xml.GetChildFloatAttribute(node, "PlaybackRateVariance", "value");
            PlaybackRateVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "PlaybackRateVariable"));
            NoteMap = XmlRel.GetHash(Xml.GetChildInnerText(node, "NoteMap"));
            ContainerName = XmlRel.GetHash(Xml.GetChildInnerText(node, "ContainerName"));
            FileName = XmlRel.GetHash(Xml.GetChildInnerText(node, "FileName"));
            VariableOutputs = XmlRel.ReadItemArray<Dat54AutomationSoundVariableOutput>(node, "VariableOutputs");
            VariableOutputsCount = (VariableOutputs?.Length ?? 0);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "FallBackSound", RelXml.HashString(FallBackSound));
            RelXml.ValueTag(sb, indent, "PlaybackRate", FloatUtil.ToString(PlaybackRate));
            RelXml.ValueTag(sb, indent, "PlaybackRateVariance", FloatUtil.ToString(PlaybackRateVariance));
            RelXml.StringTag(sb, indent, "PlaybackRateVariable", RelXml.HashString(PlaybackRateVariable));
            RelXml.StringTag(sb, indent, "NoteMap", RelXml.HashString(NoteMap));
            RelXml.StringTag(sb, indent, "ContainerName", RelXml.HashString(ContainerName));
            RelXml.StringTag(sb, indent, "FileName", RelXml.HashString(FileName));
            RelXml.WriteItemArray(sb, VariableOutputs, indent, "VariableOutputs");
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(FallBackSound);
            bw.Write(PlaybackRate);
            bw.Write(PlaybackRateVariance);
            bw.Write(PlaybackRateVariable);
            bw.Write(NoteMap);
            bw.Write(ContainerName);
            bw.Write(FileName);
            bw.Write(VariableOutputsCount);
            for (int i = 0; i < VariableOutputsCount; i++)
            {
                VariableOutputs[i].Write(bw);
            }
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0, 16 };
        }
        public override uint[] GetPackTableOffsets()
        {
            return new uint[] { 20 };
        }
    }
    [TC(typeof(EXP))] public class Dat54AutomationSoundVariableOutput : IMetaXmlItem
    {
        public int Channel { get; set; } //0x0-0x1
        public MetaHash Variable { get; set; } //0x2-0x6

        public Dat54AutomationSoundVariableOutput()
        { }
        public Dat54AutomationSoundVariableOutput(BinaryReader br)
        {
            Channel = br.ReadInt32();
            Variable = br.ReadUInt32();

            if (Channel != 0)//should be pack hash?
            { }
        }
        public void ReadXml(XmlNode node)
        {
            Channel = Xml.GetChildIntAttribute(node, "Channel", "value");
            Variable = XmlRel.GetHash(Xml.GetChildInnerText(node, "Variable"));
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Channel", Channel.ToString());
            RelXml.StringTag(sb, indent, "Variable", RelXml.HashString(Variable));
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Channel);
            bw.Write(Variable);
        }
        public override string ToString()
        {
            return Channel.ToString() + ", " + Variable.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat54ExternalStreamSound : Dat54Sound
    {
        public MetaHash Unk0 { get; set; }
        public MetaHash Unk1 { get; set; }
        public MetaHash Unk2 { get; set; }
        public MetaHash Unk3 { get; set; }

        public Dat54ExternalStreamSound(RelFile rel) : base(rel, Dat54SoundType.ExternalStreamSound)
        { }
        public Dat54ExternalStreamSound(RelData d, BinaryReader br) : base(d, br)
        {
            ReadChildSoundsHashes(br);

            Unk0 = br.ReadUInt32();
            Unk1 = br.ReadUInt32();

            if (ChildSoundsCount == 0)
            {
                Unk2 = br.ReadUInt32();
                Unk3 = br.ReadUInt32();
            }

            if (br.BaseStream.Position != br.BaseStream.Length)
            {

                //var bytes = new List<byte>();
                //while (br.BaseStream.Position < br.BaseStream.Length)
                //{
                //    byte b = br.ReadByte();
                //    bytes.Add(b);
                //    if (b != 0)
                //    { }//no hits here
                //}
                ////var bytearr = bytes.ToArray();

            }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            ReadChildSoundsXml(node, "EnvironmentSounds");
            Unk0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk0"));
            Unk1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk1"));
            if (ChildSoundsCount == 0)
            {
                Unk2 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk2"));
                Unk3 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk3"));
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            WriteChildSoundsXml(sb, indent, "EnvironmentSounds");
            RelXml.StringTag(sb, indent, "Unk0", RelXml.HashString(Unk0));
            RelXml.StringTag(sb, indent, "Unk1", RelXml.HashString(Unk1));
            if (ChildSoundsCount == 0)
            {
                RelXml.StringTag(sb, indent, "Unk2", RelXml.HashString(Unk2));
                RelXml.StringTag(sb, indent, "Unk3", RelXml.HashString(Unk3));
            }
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            WriteChildSoundsHashes(bw);

            bw.Write(Unk0);
            bw.Write(Unk1);

            if (ChildSoundsCount == 0)
            {
                bw.Write(Unk2);
                bw.Write(Unk3);
            }

        }
        public override uint[] GetHashTableOffsets()
        {
            var list = GetChildSoundsHashTableOffsets().ToList();
            uint offs = (uint)list.Count * 4 + 1;
            list.Add(offs);// Unk0
            list.Add(offs + 4);// Unk1
            if (ChildSoundsCount == 0)
            {
                list.Add(offs + 8);// Unk2
                list.Add(offs + 12);// Unk3
            }
            return list.ToArray();
            //return GetAudioTracksHashTableOffsets();
        }
    }
    [TC(typeof(EXP))] public class Dat54SoundSet : Dat54Sound
    {
        public int ItemCount { get; set; }
        public Dat54SoundSetItem[] Items { get; set; }

        public Dat54SoundSet(RelFile rel) : base(rel, Dat54SoundType.SoundSet)
        { }
        public Dat54SoundSet(RelData d, BinaryReader br) : base(d, br)
        {
            ItemCount = br.ReadInt32();
            Items = new Dat54SoundSetItem[ItemCount];
            ChildSoundsHashes = new MetaHash[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat54SoundSetItem(br);
                ChildSoundsHashes[i] = Items[i].ChildSound;
            }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Items = XmlRel.ReadItemArray<Dat54SoundSetItem>(node, "Items");
            ItemCount = (Items?.Length ?? 0);

            if (Items != null)
            {
                Array.Sort(Items, (a, b) => a.ScriptName.Hash.CompareTo(b.ScriptName.Hash));
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < ItemCount; i++)
            {
                offsets.Add(8 + i * 8);
            }
            return offsets.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat54SoundSetItem : IMetaXmlItem
    {
        public MetaHash ScriptName { get; set; }
        public MetaHash ChildSound { get; set; }

        public Dat54SoundSetItem()
        { }
        public Dat54SoundSetItem(BinaryReader br)
        {
            ScriptName = br.ReadUInt32();
            ChildSound = br.ReadUInt32();
        }
        public void ReadXml(XmlNode node)
        {
            ScriptName = XmlRel.GetHash(Xml.GetChildInnerText(node, "ScriptName"));
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "ScriptName", RelXml.HashString(ScriptName));
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(ScriptName);
            bw.Write(ChildSound);
        }
        public override string ToString()
        {
            return ScriptName.ToString() + ": " + ChildSound.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat54AutomationNoteMapSound : Dat54Sound
    {
        public byte MapsCount { get; set; }
        public Dat54AutomationNoteMapSoundData[] Maps { get; set; }

        public Dat54AutomationNoteMapSound(RelFile rel) : base(rel, Dat54SoundType.AutomationNoteMapSound)
        { }
        public Dat54AutomationNoteMapSound(RelData d, BinaryReader br) : base(d, br)
        {
            MapsCount = br.ReadByte();
            Maps = new Dat54AutomationNoteMapSoundData[MapsCount];
            ChildSoundsHashes = new MetaHash[MapsCount];
            for (int i = 0; i < MapsCount; i++)
            {
                Maps[i] = new Dat54AutomationNoteMapSoundData(br);
                ChildSoundsHashes[i] = Maps[i].ChildSound;// br.ReadUInt32();
            }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Maps = XmlRel.ReadItemArray<Dat54AutomationNoteMapSoundData>(node, "Maps");
            MapsCount = (byte)(Maps?.Length ?? 0);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.WriteItemArray(sb, Maps, indent, "Maps");
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(MapsCount);
            for (int i = 0; i < MapsCount; i++)
            {
                Maps[i].Write(bw);
            }
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < MapsCount; i++)
            {
                offsets.Add(4 + i * 7);
            }
            return offsets.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat54AutomationNoteMapSoundData : IMetaXmlItem
    {
        public byte NoteRangeMin { get; set; }
        public byte NoteRangeMax { get; set; }
        public byte NoteRangeType { get; set; }
        public MetaHash ChildSound { get; set; }

        public Dat54AutomationNoteMapSoundData()
        { }
        public Dat54AutomationNoteMapSoundData(BinaryReader br)
        {
            NoteRangeMin = br.ReadByte();
            NoteRangeMax = br.ReadByte();
            NoteRangeType = br.ReadByte();
            ChildSound = br.ReadUInt32();
        }
        public void ReadXml(XmlNode node)
        {
            NoteRangeMin = (byte)Xml.GetChildIntAttribute(node, "NoteRangeMin", "value");
            NoteRangeMax = (byte)Xml.GetChildIntAttribute(node, "NoteRangeMax", "value");
            NoteRangeType = (byte)Xml.GetChildIntAttribute(node, "NoteRangeType", "value");
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "NoteRangeMin", NoteRangeMin.ToString());
            RelXml.ValueTag(sb, indent, "NoteRangeMax", NoteRangeMax.ToString());
            RelXml.ValueTag(sb, indent, "NoteRangeType", NoteRangeType.ToString());
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(NoteRangeMin);
            bw.Write(NoteRangeMax);
            bw.Write(NoteRangeType);
            bw.Write(ChildSound);
        }
        public override string ToString()
        {
            return NoteRangeMin.ToString() + ": " + NoteRangeMax.ToString() + ": " + NoteRangeType.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat54SoundSetList : Dat54Sound
    {
        public uint SoundSetsCount { get; set; }
        public MetaHash[] SoundSets { get; set; }

        public Dat54SoundSetList(RelFile rel) : base(rel, Dat54SoundType.SoundSetList)
        { }
        public Dat54SoundSetList(RelData d, BinaryReader br) : base(d, br)
        {
            SoundSetsCount = br.ReadUInt32();
            SoundSets = new MetaHash[SoundSetsCount];
            for (int i = 0; i < SoundSetsCount; i++)
            {
                SoundSets[i] = br.ReadUInt32();
            }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            SoundSets = XmlRel.ReadHashItemArray(node, "SoundSets");
            SoundSetsCount = (uint)(SoundSets?.Length ?? 0);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.WriteHashItemArray(sb, SoundSets, indent, "SoundSets");
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(SoundSetsCount);
            for (int i = 0; i < SoundSetsCount; i++)
            {
                bw.Write(SoundSets[i]);
            }
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < SoundSetsCount; i++)
            {
                offsets.Add(4 + i * 4);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetSoundHashes()
        {
            return SoundSets;
        }
    }
    [TC(typeof(EXP))] public class Dat54SoundHashList : Dat54Sound
    {
        public ushort UnkShort { get; set; }
        public uint SoundHashesCount { get; set; }
        public MetaHash[] SoundHashes { get; set; }

        public Dat54SoundHashList(RelFile rel) : base(rel, Dat54SoundType.SoundHashList)
        { }
        public Dat54SoundHashList(RelData d, BinaryReader br) : base(d, br)
        {
            UnkShort = br.ReadUInt16();
            SoundHashesCount = br.ReadUInt32();
            SoundHashes = new MetaHash[SoundHashesCount];
            for (int i = 0; i < SoundHashesCount; i++)
            {
                SoundHashes[i] = br.ReadUInt32();
            }
            if (br.BaseStream.Position != br.BaseStream.Length)
            { }
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            UnkShort = (ushort)Xml.GetChildUIntAttribute(node, "UnkShort", "value");
            SoundHashes = XmlRel.ReadHashItemArray(node, "SoundHashes");
            SoundHashesCount = (uint)(SoundHashes?.Length ?? 0);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "UnkShort", UnkShort.ToString());
            RelXml.WriteHashItemArray(sb, SoundHashes, indent, "SoundHashes");
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(UnkShort);
            bw.Write(SoundHashesCount);
            for (int i = 0; i < SoundHashesCount; i++)
            {
                bw.Write(SoundHashes[i]);
            }
        }
        public override MetaHash[] GetSoundHashes()
        {
            return SoundHashes;
        }
    }


    #endregion




    #region dat151


    public enum Dat151RelType : byte //not sure how correct these are?
    {
        Collision = 1, //maybe for vehicle
        VehicleTrailer = 2,
        Vehicle = 3,
        VehicleEngine = 4,
        AudioMaterial = 5,
        StaticEmitter = 6, //radio emitters only, se_
        EntityEmitter = 7, //ee_, entity emitters for props such as fans, radars, etc
        Helicopter = 8,
        MeleeCombat = 9, //MeleeCombat
        SpeechContext = 11, //eg. default_speech_context, provoke, apologise, run, etc. contains reference to SpeechChoice
        SpeechChoice = 12, //eg. default_speech_context_sc, SpeechChat? SpeechController..? child of SpeechContext, Unk13
        SpeechChoice2 = 13, //eg. greet_virtual_sc (has SpeechContext children eg. greeting_evening, morning) - VirtualSpeechChoice..? also can have SpeechChoice children instead
        SpeechParams = 14,
        SpeechContextList = 15, //contains a list of SpeechContext objects. greetings, insults, reactions, provoke, etc. dlc_btl_nightclub_scl, dlc_btl_nightclub_queue_scl
        Boat = 16, //and submarines
        Weapon = 17,//individual weapons (and _npc weapons)
        Shoe = 18, //footsteps_generic, shoe_, etc.
        Unk22 = 22, //player/creature foosteps volumes? player_one, player_two, etc, as well as animals a_c_, etc, run, walk, stairs, vaulk, stealth, etc.
        Unk23 = 23, //related to footsteps, connected to AudioMaterial
        RadioStationList = 24, //RadioStationList? repl_music_station_list_03
        RadioStation = 25,
        RadioMusic = 26,
        Unk27 = 27, //radio_track_category_ back-to-back timings.
        Unk28 = 28, //ped relations to police scanner reports?
        RaceToPedVoiceGroup = 29, // Ped Race Ped Voice Group
        PedVoiceGroup = 30, //maybe Ped Ped Voice Group?
        PedType = 31,//ped category? jewish, street, airport, etc
        StaticEmitterList = 32, //contains a list of StaticEmitters used in the world.
        PoliceScannerReport = 33, // scripted_scanner_report_ etc
        PoliceScannerLocation = 35,
        PoliceScannerLocationList = 36,
        AmbientZone = 37, //zones for ambient rules.
        AmbientRule = 38, //ar_, according to GDC conference, an ambient rule contains information on a sound's position relative to the zone.
        AmbientZoneList = 39, //contains a list of AmbientZones used in the world.
        AmbientStreamList = 40, //contains eg amb_stream_bird_01
        AmbienceBankMap = 41, //assigns audio bank containers to the ambience system, ambience_bank_map_autogenerated
        AmbientZoneParams = 42, //connected to AmbientZones, something related to nearby props?
        Interior = 44,
        InteriorRoomParams = 45, //connected to InteriorRooms.
        InteriorRoom = 46,
        Door = 47,
        DoorParams = 48, //DoorType? relations to Door. dlc_h4_dtp_vertical_slide_door
        DoorList = 49, //doors/gates
        WeaponAudioItem = 50,//assigns weapon entries (player, npc, etc) to an audio item entry
        Climbing = 51, //Climbing lists of climbing, wood, chainlink, etc.
        Mod = 52, //what actually is a "mod" here? a change in some audio settings maybe?
        Train = 53,
        WeatherType = 54, //connected to WeatherTypeList
        WeatherTypeList = 55, //only one in the entire game.dat, named weathertypelist. (most child names found in weather.xml)
        Bicycle = 56,
        Aeroplane = 57,
        StemMix = 59, //StemMix, defines the 8-stem stereo mix used for the score, prefixed sm_. child of moods.
        Mood = 62,//_md, moods define transitions and stem behavior of scores.
        StartTrackAction = 63,
        StopTrackAction = 64,
        SetMoodAction = 65,
        PlayerAction = 66,
        StartOneShotAction = 67,
        StopOneShotAction = 68,
        MusicBeat = 69, // SetMoodBeat? suffixed _beat. 
        MusicBar = 70, // something about bars.
        DependentAmbience = 71, //prefixed da_, connected to AmbientZone's external parameters (usually crickets/other animals, day/night?)
        Unk72 = 72,//collision/bullet impacts?
        AnimalParams = 73,
        AnimalSounds = 74,//animal sounds - links to speech.dat somehow?
        VehicleScannerColourList = 75, //VehicleScannerColourList ? contains all police scanner colours and prefixes for vehicles
        VehicleScannerParams = 76, // _scanner_params
        Unk77 = 77, // "default"  possibly connected to Unk96
        MicrophoneList = 78,
        Microphone = 79, //Microphone? _mic
        VehicleRecord = 80, //vehicle record audio (YVR)
        VehicleRecordList = 81,
        AnimalFootstepsSounds = 82, //the actual sounds used in AnimalFootsteps
        AnimalFootsteps = 83, //something to do with animals
        ShoeList = 84, //contains a list of Shoe objects
        Cloth = 85, //Cloth, clothing items, bags, etc.
        ClothList = 86, //ClothList, all sorts of clothing stuff, bags, rappel gear, parachute gear, pants, shorts, etc. references ClothType
        Explosion = 87,
        VehicleEngineGranular = 88, //granular engine system, _granular_engine
        ShoreLinePool = 90,
        ShoreLineLake = 91,
        ShoreLineRiver = 92,
        ShoreLineOcean = 93,
        ShoreLineList = 94,
        Unk95 = 95, //StartForceRadioTrackAction ? children of "ForceRadioTrackAction"
        Unk96 = 96, //connected to Unk22's animal/creatures?
        RadioDJSpeechAction = 98,
        Unk99 = 99,
        Tunnel = 100, //Tunnels tunnels_in/out
        Alarm = 101,
        FadeOutRadioAction = 102,
        FadeInRadioAction = 103,
        ForceRadioTrackAction = 104, //suffixed _frta
        SlowMoSettings = 105, //SlowMotion settings for weapons, jumps, other slow squences etc.
        Scenario = 106, //eg world_human_musician
        AudioOcclusionOverride = 107, //world changes, broken window vs fixed windows at certain interiors (Michael's house, car showroom, etc)
        ElectricEngine = 108,  //voltic_electric_engine
        Unk109 = 109,
        Unk110 = 110, //conversation/speech related - for scenarios?
        AircraftWarningSettings = 111,
        Unk112 = 112, //conversation/speech related? contains refs to Unk110
        CopDispatchInteractionSettings = 113, //cop_dispatch_interaction_settings
        RadioTrackEvents = 114, //or RadioTrackTimes? prefixed rtt_, assigns 
        Unk115 = 115,//links to StaticEmitters
        Unk116 = 116,//tennis_vfx_settings
        DoorModel = 117, //assigns door models to Door entriees. prefixed dasl_ followed by hash of door model. (DoorAssetLink?)
        Unk118 = 118,
        Unk119 = 119, //Foilage? foilage, prop_bush_lrg_02
        RadioTrackList = 120,
        MacsModelsOverrides = 121, //or ModelList? relations to Mod. macs_models_overrides
        RadioStationList2 = 124, // radio override something?
    }

    [TC(typeof(EXP))] public class Dat151RelData : RelData
    {
        public Dat151RelType Type { get; set; }
        public uint NameTableOffset { get; set; }

        public Dat151RelData(RelFile rel) : base(rel) { }
        public Dat151RelData(RelFile rel, Dat151RelType type) : base(rel)
        {
            Type = type;
            TypeID = (byte)type;
        }
        public Dat151RelData(RelData d, BinaryReader br) : base(d)
        {
            Type = (Dat151RelType)TypeID;

            br.BaseStream.Position = 0; //1 byte was read already (TypeID)

            NameTableOffset = ((br.ReadUInt32() >> 8) & 0xFFFFFF);
        }


        public void WriteTypeAndOffset(BinaryWriter bw)
        {
            var val = ((NameTableOffset & 0xFFFFFF) << 8) + TypeID;
            bw.Write(val);
        }


        public override string ToString()
        {
            return GetBaseString() + ": " + Type.ToString();
        }
    }

    [TC(typeof(EXP))] public struct Dat151HashPair : IMetaXmlItem
    {
        public MetaHash Hash0 { get; set; }
        public MetaHash Hash1 { get; set; }

        public Dat151HashPair(BinaryReader br)
        {
            Hash0 = br.ReadUInt32();
            Hash1 = br.ReadUInt32();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Hash0);
            bw.Write(Hash1);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Hash0", RelXml.HashString(Hash0));
            RelXml.StringTag(sb, indent, "Hash1", RelXml.HashString(Hash1));
        }
        public void ReadXml(XmlNode node)
        {
            Hash0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Hash0"));
            Hash1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Hash1"));
        }
        public override string ToString()
        {
            return Hash0.ToString() + ": " + Hash1.ToString();
        }
    }
    [TC(typeof(EXP))] public struct Dat151HashFloat : IMetaXmlItem
    {
        public MetaHash Hash { get; set; }
        public float Value { get; set; }

        public Dat151HashFloat(BinaryReader br)
        {
            Hash = br.ReadUInt32();
            Value = br.ReadSingle();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Hash);
            bw.Write(Value);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Hash", RelXml.HashString(Hash));
            RelXml.ValueTag(sb, indent, "Value", FloatUtil.ToString(Value));
        }
        public void ReadXml(XmlNode node)
        {
            Hash = XmlRel.GetHash(Xml.GetChildInnerText(node, "Hash"));
            Value = Xml.GetChildFloatAttribute(node, "Value", "value");
        }
        public override string ToString()
        {
            return Hash.ToString() + ": " + Value.ToString();
        }
    }


    public enum Dat151ZoneShape : uint
    {
        Box = 0,
        Sphere = 1,
        Line = 2,
    }

    [TC(typeof(EXP))] public class Dat151StaticEmitterList: Dat151RelData
    {
        public uint EmitterCount { get; set; }
        public MetaHash[] EmitterHashes { get; set; }

        public Dat151StaticEmitterList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.StaticEmitterList;
            TypeID = (byte)Type;
        }
        public Dat151StaticEmitterList(RelData d, BinaryReader br) : base(d, br)
        {
            EmitterCount = br.ReadUInt32();
            EmitterHashes = new MetaHash[EmitterCount];
            for (int i = 0; i < EmitterCount; i++)
            {
                EmitterHashes[i] = br.ReadUInt32();
            }

            long bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { } //no hits here


        }
        public override void Write(BinaryWriter bw)
        {
            //base.Write(bw);
            WriteTypeAndOffset(bw);

            bw.Write(EmitterCount);
            for (int i = 0; i < EmitterCount; i++)
            {
                bw.Write(EmitterHashes[i]);
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteHashItemArray(sb, EmitterHashes, indent, "Emitters");
        }
        public override void ReadXml(XmlNode node)
        {
            EmitterHashes = XmlRel.ReadHashItemArray(node, "Emitters");
            EmitterCount = (uint)(EmitterHashes?.Length ?? 0);
        }
        public override MetaHash[] GetGameHashes()
        {
            return EmitterHashes;
        }
    }
    [TC(typeof(EXP))] public class Dat151AmbientZone : Dat151RelData
    {
        public FlagsUint Flags0 { get; set; }
        public Dat151ZoneShape Shape { get; set; }
        public FlagsUint Flags1 { get; set; }
        public Vector3 ActivationZonePosition { get; set; }
        public float Unused01 { get; set; }
        public Vector3 ActivationZoneSize { get; set; }
        public float Unused02 { get; set; }
        public Vector4 ActivationZoneVec1 { get; set; }
        public Vector4 ActivationZoneVec2 { get; set; }
        public uint ActivationZoneAngle { get; set; }
        public Vector3 ActivationZoneVec3 { get; set; }
        public Vector3 PlaybackZonePosition { get; set; }
        public float Unused06 { get; set; }
        public Vector3 PlaybackZoneSize { get; set; }
        public float Unused07 { get; set; }
        public Vector4 PlaybackZoneVec1 { get; set; }
        public Vector4 PlaybackZoneVec2 { get; set; }
        public uint PlaybackZoneAngle { get; set; }
        public Vector3 PlaybackZoneVec3 { get; set; }
        public Vector4 UnkVec1 { get; set; }
        public Vector4 UnkVec2 { get; set; }
        public MetaHash UnkHash0 { get; set; }
        public MetaHash Scene { get; set; }
        public Vector2 UnkVec3 { get; set; }
        public FlagsUint Flags2 { get; set; }
        public byte Unk14 { get; set; }
        public byte Unk15 { get; set; }
        public byte RulesCount { get; set; }
        public byte Unk16 { get; set; }
        public MetaHash[] Rules { get; set; }

        public uint ExtParamsCount { get; set; }
        public ExtParam[] ExtParams { get; set; }
        public struct ExtParam : IMetaXmlItem
        {
            public MetaHash Name { get; set; }
            public float Value { get; set; }
            public ExtParam(BinaryReader br)
            {
                Name = br.ReadUInt32();
                Value = br.ReadSingle();
            }
            public void Write(BinaryWriter bw)
            {
                bw.Write(Name);
                bw.Write(Value);
            }
            public void WriteXml(StringBuilder sb, int indent)
            {
                RelXml.StringTag(sb, indent, "Name", RelXml.HashString(Name));
                RelXml.ValueTag(sb, indent, "Value", FloatUtil.ToString(Value));
            }
            public void ReadXml(XmlNode node)
            {
                Name = XmlRel.GetHash(Xml.GetChildInnerText(node, "Name"));
                Value = Xml.GetChildFloatAttribute(node, "Value", "value");
            }
            public override string ToString()
            {
                return Name.ToString() + ": " + FloatUtil.ToString(Value);
            }
        }



        public Dat151AmbientZone(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.AmbientZone;
            TypeID = (byte)Type;
        }
        public Dat151AmbientZone(RelData d, BinaryReader br) : base(d, br)
        {
            Flags0 = br.ReadUInt32();
            Shape = (Dat151ZoneShape)br.ReadUInt32();
            Flags1 = br.ReadUInt32();
            ActivationZonePosition = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            Unused01 = br.ReadSingle();
            ActivationZoneSize = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            Unused02 = br.ReadSingle();
            ActivationZoneVec1 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            ActivationZoneVec2 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            ActivationZoneAngle = br.ReadUInt32();//###
            ActivationZoneVec3 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            PlaybackZonePosition = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            Unused06 = br.ReadSingle();
            PlaybackZoneSize = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            Unused07 = br.ReadSingle();
            PlaybackZoneVec1 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            PlaybackZoneVec2 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            PlaybackZoneAngle = br.ReadUInt32();//###
            PlaybackZoneVec3 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            UnkVec1 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            UnkVec2 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            UnkHash0 = br.ReadUInt32();
            Scene = br.ReadUInt32();
            UnkVec3 = new Vector2(br.ReadSingle(), br.ReadSingle());

            Flags2 = br.ReadUInt32();
            Unk14 = br.ReadByte();
            Unk15 = br.ReadByte();
            RulesCount = br.ReadByte();
            Unk16 = br.ReadByte();
            Rules = new MetaHash[RulesCount];
            for (int i = 0; i < RulesCount; i++)
            {
                Rules[i] = br.ReadUInt32();
            }

            ExtParamsCount = br.ReadUInt32();
            ExtParams = new ExtParam[ExtParamsCount];
            for (int i = 0; i < ExtParamsCount; i++)
            {
                ExtParams[i] = new ExtParam(br);
            }
            if (ExtParamsCount != 0)
            { }


            #region testing

            var data = this.Data;


            long bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            {
                //byte[] remainder = br.ReadBytes((int)bytesleft);
                //for (int i = 0; i < remainder.Length; i++)
                //{
                //    if (remainder[i] != 0)
                //    { } //no hits here! probably got everything, i'm assuming the block is padded to 0x10 or something.
                //}
            }


            //RecVec(Pos01);//debug coords output
            //RecVec(Pos06);


            if (Unused01 != 0)
            { }//no hit
            if (Unused02 != 0)
            { }//no hit
            if (Unused06 != 0)
            { }//no hit
            if (Unused07 != 0)
            { }//no hit
            if (Shape != 0)
            { }//eg 1, 2
            if (Flags1 != 0)
            { }//no hit
            if (ActivationZoneAngle > 360)
            { }//no hit
            if (PlaybackZoneAngle > 360)
            { }//no hit
            if (Flags2 != 0)
            { }//eg 0xAE64583B, 0x61083310, 0xCAE96294, 0x1C376176

            if (UnkHash0 != 0)
            { }
            if (Scene != 0)
            { }

            #endregion

        }
        public override void Write(BinaryWriter bw)
        {
            //base.Write(bw);
            WriteTypeAndOffset(bw);

            bw.Write(Flags0);
            bw.Write((uint)Shape);
            bw.Write(Flags1);
            bw.Write(ActivationZonePosition.X);
            bw.Write(ActivationZonePosition.Y);
            bw.Write(ActivationZonePosition.Z);
            bw.Write(Unused01);
            bw.Write(ActivationZoneSize.X);
            bw.Write(ActivationZoneSize.Y);
            bw.Write(ActivationZoneSize.Z);
            bw.Write(Unused02);
            bw.Write(ActivationZoneVec1.X);
            bw.Write(ActivationZoneVec1.Y);
            bw.Write(ActivationZoneVec1.Z);
            bw.Write(ActivationZoneVec1.W);
            bw.Write(ActivationZoneVec2.X);
            bw.Write(ActivationZoneVec2.Y);
            bw.Write(ActivationZoneVec2.Z);
            bw.Write(ActivationZoneVec2.W);
            bw.Write(ActivationZoneAngle);//###
            bw.Write(ActivationZoneVec3.X);
            bw.Write(ActivationZoneVec3.Y);
            bw.Write(ActivationZoneVec3.Z);
            bw.Write(PlaybackZonePosition.X);
            bw.Write(PlaybackZonePosition.Y);
            bw.Write(PlaybackZonePosition.Z);
            bw.Write(Unused06);
            bw.Write(PlaybackZoneSize.X);
            bw.Write(PlaybackZoneSize.Y);
            bw.Write(PlaybackZoneSize.Z);
            bw.Write(Unused07);
            bw.Write(PlaybackZoneVec1.X);
            bw.Write(PlaybackZoneVec1.Y);
            bw.Write(PlaybackZoneVec1.Z);
            bw.Write(PlaybackZoneVec1.W);
            bw.Write(PlaybackZoneVec2.X);
            bw.Write(PlaybackZoneVec2.Y);
            bw.Write(PlaybackZoneVec2.Z);
            bw.Write(PlaybackZoneVec2.W);
            bw.Write(PlaybackZoneAngle);//###
            bw.Write(PlaybackZoneVec3.X);
            bw.Write(PlaybackZoneVec3.Y);
            bw.Write(PlaybackZoneVec3.Z);
            bw.Write(UnkVec1.X);
            bw.Write(UnkVec1.Y);
            bw.Write(UnkVec1.Z);
            bw.Write(UnkVec1.W);
            bw.Write(UnkVec2.X);
            bw.Write(UnkVec2.Y);
            bw.Write(UnkVec2.Z);
            bw.Write(UnkVec2.W);
            bw.Write(UnkHash0);
            bw.Write(Scene);
            bw.Write(UnkVec3.X);
            bw.Write(UnkVec3.Y);

            bw.Write(Flags2);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(RulesCount);
            bw.Write(Unk16);
            for (int i = 0; i < RulesCount; i++)
            {
                bw.Write(Rules[i]);
            }

            bw.Write(ExtParamsCount);
            for (int i = 0; i < ExtParamsCount; i++)
            {
                ExtParams[i].Write(bw);
            }
            if (ExtParamsCount != 0)
            { }

            while ((bw.BaseStream.Position & 0xF) != 0) bw.Write((byte)0); //pad out to next 16 bytes

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags0", "0x" + Flags0.Hex);
            RelXml.StringTag(sb, indent, "Shape", Shape.ToString());
            RelXml.ValueTag(sb, indent, "Flags1", "0x" + Flags1.Hex);
            RelXml.SelfClosingTag(sb, indent, "ActivationZonePosition " + FloatUtil.GetVector3XmlString(ActivationZonePosition));
            RelXml.SelfClosingTag(sb, indent, "ActivationZoneSize " + FloatUtil.GetVector3XmlString(ActivationZoneSize));
            RelXml.SelfClosingTag(sb, indent, "ActivationZoneVec1 " + FloatUtil.GetVector4XmlString(ActivationZoneVec1));
            RelXml.SelfClosingTag(sb, indent, "ActivationZoneVec2 " + FloatUtil.GetVector4XmlString(ActivationZoneVec2));
            RelXml.ValueTag(sb, indent, "ActivationZoneAngle", ActivationZoneAngle.ToString());
            RelXml.SelfClosingTag(sb, indent, "ActivationZoneVec3 " + FloatUtil.GetVector3XmlString(ActivationZoneVec3));
            RelXml.SelfClosingTag(sb, indent, "PlaybackZonePosition " + FloatUtil.GetVector3XmlString(PlaybackZonePosition));
            RelXml.SelfClosingTag(sb, indent, "PlaybackZoneSize " + FloatUtil.GetVector3XmlString(PlaybackZoneSize));
            RelXml.SelfClosingTag(sb, indent, "PlaybackZoneVec1 " + FloatUtil.GetVector4XmlString(PlaybackZoneVec1));
            RelXml.SelfClosingTag(sb, indent, "PlaybackZoneVec2 " + FloatUtil.GetVector4XmlString(PlaybackZoneVec2));
            RelXml.ValueTag(sb, indent, "PlaybackZoneAngle", PlaybackZoneAngle.ToString());
            RelXml.SelfClosingTag(sb, indent, "PlaybackZoneVec3 " + FloatUtil.GetVector3XmlString(PlaybackZoneVec3));
            RelXml.SelfClosingTag(sb, indent, "UnkVec1 " + FloatUtil.GetVector4XmlString(UnkVec1));
            RelXml.SelfClosingTag(sb, indent, "UnkVec2 " + FloatUtil.GetVector4XmlString(UnkVec2));
            RelXml.StringTag(sb, indent, "UnkHash0", RelXml.HashString(UnkHash0));
            RelXml.StringTag(sb, indent, "Scene", RelXml.HashString(Scene));
            RelXml.SelfClosingTag(sb, indent, "UnkVec3 " + FloatUtil.GetVector2XmlString(UnkVec3));
            RelXml.ValueTag(sb, indent, "Flags2", "0x" + Flags2.Hex);
            RelXml.ValueTag(sb, indent, "Unk14", Unk14.ToString());
            RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.WriteHashItemArray(sb, Rules, indent, "Rules");
            RelXml.WriteItemArray(sb, ExtParams, indent, "ExtParams");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags0 = Xml.GetChildUIntAttribute(node, "Flags0", "value");
            Shape = Xml.GetEnumValue<Dat151ZoneShape>(Xml.GetChildInnerText(node, "Shape"));
            Flags1 = Xml.GetChildUIntAttribute(node, "Flags1", "value");
            ActivationZonePosition = Xml.GetChildVector3Attributes(node, "ActivationZonePosition");
            ActivationZoneSize = Xml.GetChildVector3Attributes(node, "ActivationZoneSize");
            ActivationZoneVec1 = Xml.GetChildVector4Attributes(node, "ActivationZoneVec1");
            ActivationZoneVec2 = Xml.GetChildVector4Attributes(node, "ActivationZoneVec2");
            ActivationZoneAngle = Xml.GetChildUIntAttribute(node, "ActivationZoneAngle", "value");
            ActivationZoneVec3 = Xml.GetChildVector3Attributes(node, "ActivationZoneVec3");
            PlaybackZonePosition = Xml.GetChildVector3Attributes(node, "PlaybackZonePosition");
            PlaybackZoneSize = Xml.GetChildVector3Attributes(node, "PlaybackZoneSize");
            PlaybackZoneVec1 = Xml.GetChildVector4Attributes(node, "PlaybackZoneVec1");
            PlaybackZoneVec2 = Xml.GetChildVector4Attributes(node, "PlaybackZoneVec2");
            PlaybackZoneAngle = Xml.GetChildUIntAttribute(node, "PlaybackZoneAngle", "value");
            PlaybackZoneVec3 = Xml.GetChildVector3Attributes(node, "PlaybackZoneVec3");
            UnkVec1 = Xml.GetChildVector4Attributes(node, "UnkVec1");
            UnkVec2 = Xml.GetChildVector4Attributes(node, "UnkVec2");
            UnkHash0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "UnkHash0"));
            Scene = XmlRel.GetHash(Xml.GetChildInnerText(node, "Scene"));
            UnkVec3 = Xml.GetChildVector2Attributes(node, "UnkVec3");
            Flags2 = Xml.GetChildUIntAttribute(node, "Flags2", "value");
            Unk14 = (byte)Xml.GetChildUIntAttribute(node, "Unk14", "value");
            Unk15 = (byte)Xml.GetChildUIntAttribute(node, "Unk15", "value");
            Unk16 = (byte)Xml.GetChildUIntAttribute(node, "Unk16", "value");
            Rules = XmlRel.ReadHashItemArray(node, "Rules");
            RulesCount = (byte)(Rules?.Length ?? 0);
            ExtParams = XmlRel.ReadItemArray<ExtParam>(node, "ExtParams");
            ExtParamsCount = (uint)(ExtParams?.Length ?? 0);
        }
        public override MetaHash[] GetMixerHashes()
        {
            return new[] { Scene };
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            list.Add(UnkHash0);
            if (Rules != null) list.AddRange(Rules);
            if (ExtParams != null)
            {
                foreach (var ep in ExtParams) list.Add(ep.Name);
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151AmbientRule : Dat151RelData
    {
        public FlagsUint Flags0 { get; set; }
        public FlagsUint Flags1 { get; set; }
        public FlagsUint Flags2 { get; set; }
        public Vector3 Position { get; set; }
        public FlagsUint Flags3 { get; set; }    //0
        public MetaHash ChildSound { get; set; }
        public MetaHash Category { get; set; }
        public FlagsUint Flags4 { get; set; }    //0
        public FlagsUint Flags5 { get; set; }    //0xFFFFFFFF
        public FlagsUint Flags6 { get; set; }    //0
        public float Unk01 { get; set; }        //1, 5, 100, ...
        public float InnerRad { get; set; }        //0, 4,         ...     100 ... min value?
        public float OuterRad { get; set; }        //15, 16, 12, 10, 20,   300 ... max value?
        public ushort StartTime { get; set; }   //game minutes
        public ushort EndTime { get; set; }
        public FlagsUshort Unk06 { get; set; }  //0..600
        public FlagsUshort Unk07 { get; set; }  //0..150
        public FlagsByte Unk08 { get; set; }    //0,1,2
        public FlagsByte Unk09 { get; set; }    //0,1,2
        public FlagsByte Unk10 { get; set; }    //1,2,3,4,8,255
        public FlagsByte Unk11 { get; set; }    //1,2,3,4,5,6,8,10,255
        public FlagsByte Unk12 { get; set; }    //0, 50, 80, 100
        public FlagsByte Unk13 { get; set; }    //1,2,3,5
        public ushort ExtParamsCount { get; set; } //0,1,2,4
        public ExtParam[] ExtParams { get; set; }

        public struct ExtParam : IMetaXmlItem
        {
            public MetaHash Hash;
            public float Value;
            public FlagsUint Flags;
            public ExtParam(BinaryReader br)
            {
                Hash = br.ReadUInt32();
                Value = br.ReadSingle();
                Flags = br.ReadUInt32();
            }
            public void Write(BinaryWriter bw)
            {
                bw.Write(Hash);
                bw.Write(Value);
                bw.Write(Flags);
            }
            public void WriteXml(StringBuilder sb, int indent)
            {
                RelXml.StringTag(sb, indent, "Hash", RelXml.HashString(Hash));
                RelXml.ValueTag(sb, indent, "Value", FloatUtil.ToString(Value));
                RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            }
            public void ReadXml(XmlNode node)
            {
                Hash = XmlRel.GetHash(Xml.GetChildInnerText(node, "Hash"));
                Value = Xml.GetChildFloatAttribute(node, "Value", "value");
                Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            }
            public override string ToString()
            {
                return Hash.ToString() + ": " + FloatUtil.ToString(Value) + ": " + Flags.ToString();
            }
        }


        public Dat151AmbientRule(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.AmbientRule;
            TypeID = (byte)Type;
        }
        public Dat151AmbientRule(RelData d, BinaryReader br) : base(d, br)
        {
            Flags0 = br.ReadUInt32();
            Flags1 = br.ReadUInt32();
            Flags2 = br.ReadUInt32();
            Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            Flags3 = br.ReadUInt32();    //0
            ChildSound = br.ReadUInt32();
            Category = br.ReadUInt32();
            Flags4 = br.ReadUInt32();    //0
            Flags5 = br.ReadUInt32();    //0xFFFFFFFF
            Flags6 = br.ReadUInt32();    //0
            Unk01 = br.ReadSingle();    //1, 5, 100, ...
            InnerRad = br.ReadSingle();    //0, 4,         ...     100 ... min value?
            OuterRad = br.ReadSingle();    //15, 16, 12, 10, 20,   300 ... max value?
            StartTime = br.ReadUInt16();
            EndTime = br.ReadUInt16();
            Unk06 = br.ReadUInt16();    //0..600
            Unk07 = br.ReadUInt16();    //0..150
            Unk08 = br.ReadByte();      //0,1,2
            Unk09 = br.ReadByte();      //0,1,2
            Unk10 = br.ReadByte();      //1,2,3,4,8,255
            Unk11 = br.ReadByte();      //1,2,3,4,5,6,8,10,255
            Unk12 = br.ReadByte();      //0, 50, 80, 100
            Unk13 = br.ReadByte();      //1,2,3,5
            ExtParamsCount = br.ReadUInt16();  //0,1,2,4

            if (ExtParamsCount > 0)
            {
                ExtParams = new ExtParam[ExtParamsCount];
                for (int i = 0; i < ExtParamsCount; i++)
                {
                    ExtParams[i] = new ExtParam(br);
                }
                //array seems to be padded to multiples of 16 bytes. (read the rest here)
                int brem = (16 - ((ExtParamsCount * 12) % 16)) % 16;
                if (brem > 0)
                {
                    byte[] brema = br.ReadBytes(brem);
                    //for (int i = 0; i < brem; i++)
                    //{
                    //    if (brema[i] != 0)
                    //    { } //check all remaining bytes are 0 - never hit here
                    //}
                }
            }


            #region testing

            switch (Unk06.Value)
            {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                case 10:
                case 11:
                case 12:
                case 13:
                case 14:
                case 15:
                case 16:
                case 18:
                case 20:
                case 22:
                case 24:
                case 25:
                case 26:
                case 30:
                case 32:
                case 35:
                case 40:
                case 45:
                case 48:
                case 50:
                case 51:
                case 54:
                case 55:
                case 57:
                case 60:
                case 64:
                case 65:
                case 70:
                case 75:
                case 80:
                case 90:
                case 95:
                case 97:
                case 100:
                case 120:
                case 125:
                case 130:
                case 135:
                case 140:
                case 145:
                case 150:
                case 160:
                case 170:
                case 178:
                case 180:
                case 190:
                case 200:
                case 220:
                case 225:
                case 240:
                case 245:
                case 250:
                case 300:
                case 350:
                case 500:
                case 600:
                    break;
                default:
                    break;
            }
            switch (Unk07.Value)
            {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 7:
                case 8:
                case 9:
                case 10:
                case 12:
                case 15:
                case 17:
                case 20:
                case 21:
                case 22:
                case 25:
                case 27:
                case 30:
                case 32:
                case 35:
                case 40:
                case 50:
                case 60:
                case 100:
                case 150:
                    break;
                default:
                    break;
            }
            switch (Unk08.Value)
            {
                case 0:
                case 1:
                case 2:
                    break;
                default:
                    break;
            }
            switch (Unk09.Value)
            {
                case 0:
                case 1:
                case 2:
                    break;
                default:
                    break;
            }
            switch (Unk10.Value)
            {
                case 1:
                case 2:
                case 3:
                case 4:
                case 8:
                case 255:
                    break;
                default:
                    break;
            }
            switch (Unk11.Value)
            {
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                case 8:
                case 10:
                case 255:
                    break;
                default:
                    break;
            }
            switch (Unk12.Value)
            {
                case 0:
                case 50:
                case 80:
                case 100:
                    break;
                default:
                    break;
            }
            switch (Unk13.Value)
            {
                case 1:
                case 2:
                case 3:
                case 5:
                    break;
                default:
                    break;
            }
            switch (ExtParamsCount)
            {
                case 0:
                case 1:
                case 2:
                case 4:
                    break;
                default:
                    break;
            }



            //if ((Position.X != 0) || (Position.Y != 0) || (Position.Z != 0))
            //{
            //    FoundCoords.Add(FloatUtil.GetVector3String(Position) + ", " + GetNameString());
            //}

            long bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }


            #endregion

        }
        public override void Write(BinaryWriter bw)
        {
            //base.Write(bw);
            WriteTypeAndOffset(bw);

            bw.Write(Flags0);
            bw.Write(Flags1);
            bw.Write(Flags2);
            bw.Write(Position.X);
            bw.Write(Position.Y);
            bw.Write(Position.Z);
            bw.Write(Flags3);
            bw.Write(ChildSound);
            bw.Write(Category);
            bw.Write(Flags4);
            bw.Write(Flags5);
            bw.Write(Flags6);
            bw.Write(Unk01);
            bw.Write(InnerRad);
            bw.Write(OuterRad);
            bw.Write(StartTime);
            bw.Write(EndTime);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(ExtParamsCount);

            if (ExtParamsCount > 0)
            {
                for (int i = 0; i < ExtParamsCount; i++)
                {
                    ExtParams[i].Write(bw);
                }
                //array seems to be padded to multiples of 16 bytes. (write the rest here)
                while ((bw.BaseStream.Position & 0xF) != 0) bw.Write((byte)0); //pad out to next 16 bytes
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags0", "0x" + Flags0.Hex);
            RelXml.ValueTag(sb, indent, "Flags1", "0x" + Flags1.Hex);
            RelXml.ValueTag(sb, indent, "Flags2", "0x" + Flags2.Hex);
            RelXml.SelfClosingTag(sb, indent, "Position " + FloatUtil.GetVector3XmlString(Position));
            RelXml.ValueTag(sb, indent, "Flags3", "0x" + Flags3.Hex);
            RelXml.StringTag(sb, indent, "ChildSound", RelXml.HashString(ChildSound));
            RelXml.StringTag(sb, indent, "Category", RelXml.HashString(Category));
            RelXml.ValueTag(sb, indent, "Flags4", "0x" + Flags4.Hex);
            RelXml.ValueTag(sb, indent, "Flags5", "0x" + Flags5.Hex);
            RelXml.ValueTag(sb, indent, "Flags6", "0x" + Flags6.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", FloatUtil.ToString(Unk01));
            RelXml.ValueTag(sb, indent, "InnerRad", FloatUtil.ToString(InnerRad));
            RelXml.ValueTag(sb, indent, "OuterRad", FloatUtil.ToString(OuterRad));
            RelXml.ValueTag(sb, indent, "StartTime", StartTime.ToString());
            RelXml.ValueTag(sb, indent, "EndTime", EndTime.ToString());
            RelXml.ValueTag(sb, indent, "Unk06", Unk06.Value.ToString());
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.Value.ToString());
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.Value.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.Value.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.Value.ToString());
            RelXml.ValueTag(sb, indent, "Unk11", Unk11.Value.ToString());
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.Value.ToString());
            RelXml.ValueTag(sb, indent, "Unk13", Unk13.Value.ToString());
            RelXml.WriteItemArray(sb, ExtParams, indent, "ExtParams");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags0 = Xml.GetChildUIntAttribute(node, "Flags0", "value");
            Flags1 = Xml.GetChildUIntAttribute(node, "Flags1", "value");
            Flags2 = Xml.GetChildUIntAttribute(node, "Flags2", "value");
            Position = Xml.GetChildVector3Attributes(node, "Position");
            Flags3 = Xml.GetChildUIntAttribute(node, "Flags3", "value");
            ChildSound = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound"));
            Category = XmlRel.GetHash(Xml.GetChildInnerText(node, "Category"));
            Flags4 = Xml.GetChildUIntAttribute(node, "Flags4", "value");
            Flags5 = Xml.GetChildUIntAttribute(node, "Flags5", "value");
            Flags6 = Xml.GetChildUIntAttribute(node, "Flags6", "value");
            Unk01 = Xml.GetChildFloatAttribute(node, "Unk01", "value");
            InnerRad = Xml.GetChildFloatAttribute(node, "InnerRad", "value");
            OuterRad = Xml.GetChildFloatAttribute(node, "OuterRad", "value");
            StartTime = (ushort)Xml.GetChildUIntAttribute(node, "StartTime", "value");
            EndTime = (ushort)Xml.GetChildUIntAttribute(node, "EndTime", "value");
            Unk06 = (ushort)Xml.GetChildUIntAttribute(node, "Unk06", "value");
            Unk07 = (ushort)Xml.GetChildUIntAttribute(node, "Unk07", "value");
            Unk08 = (byte)Xml.GetChildUIntAttribute(node, "Unk08", "value");
            Unk09 = (byte)Xml.GetChildUIntAttribute(node, "Unk09", "value");
            Unk10 = (byte)Xml.GetChildUIntAttribute(node, "Unk10", "value");
            Unk11 = (byte)Xml.GetChildUIntAttribute(node, "Unk11", "value");
            Unk12 = (byte)Xml.GetChildUIntAttribute(node, "Unk12", "value");
            Unk13 = (byte)Xml.GetChildUIntAttribute(node, "Unk13", "value");
            ExtParams = XmlRel.ReadItemArray<ExtParam>(node, "ExtParams");
            ExtParamsCount = (ushort)(ExtParams?.Length ?? 0);
        }
        public override MetaHash[] GetCategoryHashes()
        {
            return new[] { Category };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { ChildSound };
        }
    }
    [TC(typeof(EXP))] public class Dat151AmbientZoneList : Dat151RelData
    {
        public uint ZoneCount { get; set; }
        public MetaHash[] ZoneHashes { get; set; }

        public Dat151AmbientZoneList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.AmbientZoneList;
            TypeID = (byte)Type;
        }
        public Dat151AmbientZoneList(RelData d, BinaryReader br) : base(d, br)
        {
            ZoneCount = br.ReadUInt32();
            ZoneHashes = new MetaHash[ZoneCount];
            for (int i = 0; i < ZoneCount; i++)
            {
                ZoneHashes[i] = br.ReadUInt32();
            }

            long bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { } //no hits here

        }
        public override void Write(BinaryWriter bw)
        {
            //base.Write(bw);
            WriteTypeAndOffset(bw);

            bw.Write(ZoneCount);
            for (int i = 0; i < ZoneCount; i++)
            {
                bw.Write(ZoneHashes[i]);
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteHashItemArray(sb, ZoneHashes, indent, "Zones");
        }
        public override void ReadXml(XmlNode node)
        {
            ZoneHashes = XmlRel.ReadHashItemArray(node, "Zones");
            ZoneCount = (uint)(ZoneHashes?.Length ?? 0);
        }
        public override MetaHash[] GetGameHashes()
        {
            return ZoneHashes;
        }
    }
    [TC(typeof(EXP))] public class Dat151StaticEmitter : Dat151RelData
    {
        public FlagsUint Flags { get; set; }//flags
        public MetaHash Unk01 { get; set; }
        public MetaHash RadioStation { get; set; }
        public Vector3 Position { get; set; }
        public float Unk06 { get; set; }
        public float Unk07 { get; set; }
        public int Unk08 { get; set; }
        public short Unk09 { get; set; }
        public short Unk10 { get; set; }
        public int Unk11 { get; set; }
        public MetaHash Interior { get; set; }
        public MetaHash Room { get; set; }
        public MetaHash Unk13 { get; set; }
        public float Unk14 { get; set; }
        public ushort Unk15 { get; set; }
        public ushort Unk16 { get; set; }
        public MetaHash Alarm { get; set; }
        public MetaHash Unk18 { get; set; }
        public int Unk19 { get; set; }
        public FlagsUint Unk20 { get; set; }//0x05A00000
        public float Unk21 { get; set; }
        public float Unk22 { get; set; }

        public Dat151StaticEmitter(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.StaticEmitter;
            TypeID = (byte)Type;
        }
        public Dat151StaticEmitter(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();//flags
            Unk01 = br.ReadUInt32();
            RadioStation = br.ReadUInt32();
            Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            Unk06 = br.ReadSingle();
            Unk07 = br.ReadSingle();
            Unk08 = br.ReadInt32();
            Unk09 = br.ReadInt16();
            Unk10 = br.ReadInt16();
            Unk11 = br.ReadInt32();
            Interior = br.ReadUInt32();
            Room = br.ReadUInt32();
            Unk13 = br.ReadUInt32();
            Unk14 = br.ReadSingle();
            Unk15 = br.ReadUInt16();
            Unk16 = br.ReadUInt16();
            Alarm = br.ReadUInt32();
            Unk18 = br.ReadUInt32();
            Unk19 = br.ReadInt32();
            Unk20 = br.ReadUInt32();//0x05A00000
            Unk21 = br.ReadSingle();
            Unk22 = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);
            bw.Write(Flags);//flags
            bw.Write(Unk01);
            bw.Write(RadioStation);
            bw.Write(Position.X);
            bw.Write(Position.Y);
            bw.Write(Position.Z);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Interior);
            bw.Write(Room);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Alarm);
            bw.Write(Unk18);
            bw.Write(Unk19);
            bw.Write(Unk20);//0x05A00000
            bw.Write(Unk21);
            bw.Write(Unk22);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "RadioStation", RelXml.HashString(RadioStation));
            RelXml.SelfClosingTag(sb, indent, "Position " + FloatUtil.GetVector3XmlString(Position));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", FloatUtil.ToString(Unk07));
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.ValueTag(sb, indent, "Unk11", Unk11.ToString());
            RelXml.StringTag(sb, indent, "Interior", RelXml.HashString(Interior));
            RelXml.StringTag(sb, indent, "Room", RelXml.HashString(Room));
            RelXml.StringTag(sb, indent, "Unk13", RelXml.HashString(Unk13));
            RelXml.ValueTag(sb, indent, "Unk14", FloatUtil.ToString(Unk14));
            RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.StringTag(sb, indent, "Alarm", RelXml.HashString(Alarm));
            RelXml.StringTag(sb, indent, "Unk18", RelXml.HashString(Unk18));
            RelXml.ValueTag(sb, indent, "Unk19", Unk19.ToString());
            RelXml.ValueTag(sb, indent, "Unk20", "0x" + Unk20.Hex);
            RelXml.ValueTag(sb, indent, "Unk21", FloatUtil.ToString(Unk21));
            RelXml.ValueTag(sb, indent, "Unk22", FloatUtil.ToString(Unk22));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            RadioStation = XmlRel.GetHash(Xml.GetChildInnerText(node, "RadioStation"));
            Position = Xml.GetChildVector3Attributes(node, "Position");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildFloatAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildIntAttribute(node, "Unk08", "value");
            Unk09 = (short)Xml.GetChildIntAttribute(node, "Unk09", "value");
            Unk10 = (short)Xml.GetChildIntAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildIntAttribute(node, "Unk11", "value");
            Interior = XmlRel.GetHash(Xml.GetChildInnerText(node, "Interior"));
            Room = XmlRel.GetHash(Xml.GetChildInnerText(node, "Room"));
            Unk13 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk13"));
            Unk14 = Xml.GetChildFloatAttribute(node, "Unk14", "value");
            Unk15 = (ushort)Xml.GetChildUIntAttribute(node, "Unk15", "value");
            Unk16 = (ushort)Xml.GetChildUIntAttribute(node, "Unk16", "value");
            Alarm = XmlRel.GetHash(Xml.GetChildInnerText(node, "Alarm"));
            Unk18 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk18"));
            Unk19 = Xml.GetChildIntAttribute(node, "Unk19", "value");
            Unk20 = Xml.GetChildUIntAttribute(node, "Unk20", "value");
            Unk21 = Xml.GetChildFloatAttribute(node, "Unk21", "value");
            Unk22 = Xml.GetChildFloatAttribute(node, "Unk22", "value");
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk01, Unk18 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { RadioStation, Alarm, Interior };
        }
    }
    [TC(typeof(EXP))] public class Dat151Interior : Dat151RelData
    {
        public FlagsUint Unk0 { get; set; }
        public FlagsUint Unk1 { get; set; }
        public FlagsUint Unk2 { get; set; }
        public uint RoomsCount { get; set; }
        public MetaHash[] Rooms { get; set; }

        public Dat151Interior(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Interior;
            TypeID = (byte)Type;
        }
        public Dat151Interior(RelData d, BinaryReader br) : base(d, br)
        {
            Unk0 = br.ReadUInt32();
            Unk1 = br.ReadUInt32();
            Unk2 = br.ReadUInt32();
            RoomsCount = br.ReadUInt32();
            var rooms = new MetaHash[RoomsCount];
            for (int i = 0; i < RoomsCount; i++)
            {
                rooms[i] = br.ReadUInt32();
            }
            Rooms = rooms;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk0);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(RoomsCount);
            for (int i = 0; i < RoomsCount; i++)
            {
                bw.Write(Rooms[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk0", "0x" + Unk0.Hex);
            RelXml.ValueTag(sb, indent, "Unk1", "0x" + Unk1.Hex);
            RelXml.ValueTag(sb, indent, "Unk2", "0x" + Unk2.Hex);
            RelXml.WriteHashItemArray(sb, Rooms, indent, "Rooms");
        }
        public override void ReadXml(XmlNode node)
        {
            Unk0 = Xml.GetChildUIntAttribute(node, "Unk0", "value");
            Unk1 = Xml.GetChildUIntAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildUIntAttribute(node, "Unk2", "value");
            Rooms = XmlRel.ReadHashItemArray(node, "Rooms");
            RoomsCount = (uint)(Rooms?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < RoomsCount; i++)
            {
                offsets.Add(16 + i * 4);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            return Rooms;
        }
    }
    [TC(typeof(EXP))] public class Dat151InteriorRoom : Dat151RelData
    {
        public FlagsUint Flags0 { get; set; }
        public MetaHash MloRoom { get; set; }
        public MetaHash Zone { get; set; }
        public uint Unk02 { get; set; }
        public float Unk03 { get; set; }
        public float Reverb { get; set; }
        public float Echo { get; set; }
        public MetaHash Sound { get; set; }
        public float Unk07 { get; set; }
        public float Unk08 { get; set; }
        public float Unk09 { get; set; }
        public float Unk10 { get; set; }
        public float Unk11 { get; set; }
        public float Unk12 { get; set; }
        public MetaHash Unk13 { get; set; }
        public MetaHash SoundSet { get; set; }

        public Dat151InteriorRoom(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.InteriorRoom;
            TypeID = (byte)Type;
        }
        public Dat151InteriorRoom(RelData d, BinaryReader br) : base(d, br)
        {
            Flags0 = br.ReadUInt32();
            MloRoom = br.ReadUInt32();
            Zone = br.ReadUInt32();
            Unk02 = br.ReadUInt32();
            Unk03 = br.ReadSingle();
            Reverb = br.ReadSingle();
            Echo = br.ReadSingle();
            Sound = br.ReadUInt32();
            Unk07 = br.ReadSingle();
            Unk08 = br.ReadSingle();
            Unk09 = br.ReadSingle();
            Unk10 = br.ReadSingle();
            Unk11 = br.ReadSingle();
            Unk12 = br.ReadSingle();
            Unk13 = br.ReadUInt32();
            SoundSet = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags0);
            bw.Write(MloRoom);
            bw.Write(Zone);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Reverb);
            bw.Write(Echo);
            bw.Write(Sound);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(SoundSet);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags0", "0x" + Flags0.Hex);
            RelXml.StringTag(sb, indent, "MloRoom", RelXml.HashString(MloRoom));
            RelXml.StringTag(sb, indent, "Zone", RelXml.HashString(Zone));
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Reverb", FloatUtil.ToString(Reverb));
            RelXml.ValueTag(sb, indent, "Echo", FloatUtil.ToString(Echo));
            RelXml.StringTag(sb, indent, "Sound", RelXml.HashString(Sound));
            RelXml.ValueTag(sb, indent, "Unk07", FloatUtil.ToString(Unk07));
            RelXml.ValueTag(sb, indent, "Unk08", FloatUtil.ToString(Unk08));
            RelXml.ValueTag(sb, indent, "Unk09", FloatUtil.ToString(Unk09));
            RelXml.ValueTag(sb, indent, "Unk10", FloatUtil.ToString(Unk10));
            RelXml.ValueTag(sb, indent, "Unk11", FloatUtil.ToString(Unk11));
            RelXml.ValueTag(sb, indent, "Unk12", FloatUtil.ToString(Unk12));
            RelXml.StringTag(sb, indent, "Unk13", RelXml.HashString(Unk13));
            RelXml.StringTag(sb, indent, "SoundSet", RelXml.HashString(SoundSet));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags0 = Xml.GetChildUIntAttribute(node, "Flags0", "value");
            MloRoom = XmlRel.GetHash(Xml.GetChildInnerText(node, "MloRoom"));
            Zone = XmlRel.GetHash(Xml.GetChildInnerText(node, "Zone"));
            Unk02 = Xml.GetChildUIntAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Reverb = Xml.GetChildFloatAttribute(node, "Reverb", "value");
            Echo = Xml.GetChildFloatAttribute(node, "Echo", "value");
            Sound = XmlRel.GetHash(Xml.GetChildInnerText(node, "Sound"));
            Unk07 = Xml.GetChildFloatAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildFloatAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildFloatAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildFloatAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildFloatAttribute(node, "Unk11", "value");
            Unk12 = Xml.GetChildFloatAttribute(node, "Unk12", "value");
            Unk13 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk13"));
            SoundSet = XmlRel.GetHash(Xml.GetChildInnerText(node, "SoundSet"));
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 8 };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Sound, SoundSet };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { Zone, Unk13 };
        }
    }
    [TC(typeof(EXP))] public class Dat151RadioStationList : Dat151RelData
    {
        public uint StationsCount { get; set; }
        public MetaHash[] Stations { get; set; }

        public Dat151RadioStationList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.RadioStationList;
            TypeID = (byte)Type;
        }
        public Dat151RadioStationList(RelData d, BinaryReader br) : base(d, br)
        {
            StationsCount = br.ReadUInt32();
            var tracks = new MetaHash[StationsCount];
            for (int i = 0; i < StationsCount; i++)
            {
                tracks[i] = br.ReadUInt32();
            }
            Stations = tracks;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(StationsCount);
            for (int i = 0; i < StationsCount; i++)
            {
                bw.Write(Stations[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteHashItemArray(sb, Stations, indent, "Stations");
        }
        public override void ReadXml(XmlNode node)
        {
            Stations = XmlRel.ReadHashItemArray(node, "Stations");
            StationsCount = (uint)(Stations?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < StationsCount; i++)
            {
                offsets.Add(4 + i * 4);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            return Stations;
        }
    }
    [TC(typeof(EXP))] public class Dat151RadioStation : Dat151RelData
    {
        public FlagsUint Unk00 { get; set; }
        public uint WheelPosition { get; set; }
        public uint Unk02 { get; set; }
        public ushort MusicGenre { get; set; }
        public string RadioName { get; set; }
        public ushort Unk04 { get; set; }

        public uint MusicListCount { get; set; }
        public MetaHash[] MusicList { get; set; }

        public Dat151RadioStation(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.RadioStation;
            TypeID = (byte)Type;
        }
        public Dat151RadioStation(RelData d, BinaryReader br) : base(d, br)
        {
            Unk00 = br.ReadUInt32();
            WheelPosition = br.ReadUInt32();
            Unk02 = br.ReadUInt32();
            MusicGenre = br.ReadUInt16();

            var data = br.ReadBytes(32);
            RadioName = Encoding.ASCII.GetString(data).Replace("\0", "");

            Unk04 = br.ReadUInt16();

            if (Unk04 != 0)
            { }

            MusicListCount = br.ReadUInt32();
            var tracks = new MetaHash[MusicListCount];
            for (int i = 0; i < MusicListCount; i++)
            {
                tracks[i] = br.ReadUInt32();
            }
            MusicList = tracks;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk00);
            bw.Write(WheelPosition);
            bw.Write(Unk02);
            bw.Write(MusicGenre);

            byte[] data = new byte[32];
            int len = Math.Min(RadioName?.Length ?? 0, 32);
            if (len > 0)
            {
                Encoding.ASCII.GetBytes(RadioName, 0, len, data, 0);
            }
            bw.Write(data);

            bw.Write(Unk04);

            bw.Write(MusicListCount);
            for (int i = 0; i < MusicListCount; i++)
            {
                bw.Write(MusicList[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk00", "0x" + Unk00.Hex);
            RelXml.ValueTag(sb, indent, "WheelPosition", WheelPosition.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.ValueTag(sb, indent, "MusicGenre", MusicGenre.ToString());
            RelXml.StringTag(sb, indent, "RadioName", RadioName);
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.WriteHashItemArray(sb, MusicList, indent, "MusicList");
        }
        public override void ReadXml(XmlNode node)
        {
            Unk00 = Xml.GetChildUIntAttribute(node, "Unk00", "value");
            WheelPosition = Xml.GetChildUIntAttribute(node, "WheelPosition", "value");
            Unk02 = Xml.GetChildUIntAttribute(node, "Unk02", "value");
            MusicGenre = (ushort)Xml.GetChildUIntAttribute(node, "MusicGenre", "value");
            RadioName = Xml.GetChildInnerText(node, "RadioName");
            Unk04 = (ushort)Xml.GetChildUIntAttribute(node, "Unk04", "value");
            MusicList = XmlRel.ReadHashItemArray(node, "MusicList");
            MusicListCount = (uint)(MusicList?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < MusicListCount; i++)
            {
                offsets.Add(52 + i * 4);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            return MusicList;
        }
    }
    [TC(typeof(EXP))] public class Dat151RadioMusic : Dat151RelData //name eg: radioname_music
    {
        public FlagsUint Unk00 { get; set; }
        public byte MusicType { get; set; }
        public uint Unk01 { get; set; }
        public uint Unk02 { get; set; }
        public byte Unk03 { get; set; }
        public uint Unk04 { get; set; }
        public uint Unk05 { get; set; }
        public uint Unk06 { get; set; }
        public uint Unk07 { get; set; }
        public uint Unk08 { get; set; }
        public uint Unk09 { get; set; }
        public uint Unk10 { get; set; }
        public uint Unk11 { get; set; }
        public uint Unk12 { get; set; }
        public uint Unk13 { get; set; }
        public uint Unk14 { get; set; }
        public uint Unk15 { get; set; }
        public ushort Unk16 { get; set; }
        public uint PlaylistCount { get; set; }
        public Dat151HashPair[] Playlists { get; set; }


        public Dat151RadioMusic(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.RadioMusic;
            TypeID = (byte)Type;
        }
        public Dat151RadioMusic(RelData d, BinaryReader br) : base(d, br)
        {
            Unk00 = br.ReadUInt32();
            MusicType = br.ReadByte();
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadUInt32();
            Unk03 = br.ReadByte();
            Unk04 = br.ReadUInt32();
            Unk05 = br.ReadUInt32();
            Unk06 = br.ReadUInt32();
            Unk07 = br.ReadUInt32();
            Unk08 = br.ReadUInt32();
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadUInt32();
            Unk11 = br.ReadUInt32();
            Unk12 = br.ReadUInt32();
            Unk13 = br.ReadUInt32();
            Unk14 = br.ReadUInt32();
            Unk15 = br.ReadUInt32();
            Unk16 = br.ReadUInt16();
            PlaylistCount = br.ReadUInt32();

            Dat151HashPair[] items = new Dat151HashPair[PlaylistCount];
            for (int i = 0; i < PlaylistCount; i++)
            {
                items[i] = new Dat151HashPair(br);
            }
            this.Playlists = items;



            if (Unk04 != 0)
            { }
            if (Unk05 != 0)
            { }
            if (Unk06 != 0)
            { }
            if (Unk07 != 0)
            { }
            if (Unk08 != 0)
            { }
            if (Unk09 != 0)
            { }
            if (Unk10 != 0)
            { }
            if (Unk11 != 0)
            { }
            if (Unk12 != 0)
            { }
            if (Unk13 != 0)
            { }


            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk00);
            bw.Write(MusicType);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(PlaylistCount);
            for (int i = 0; i < PlaylistCount; i++)
            {
                Playlists[i].Write(bw);
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk00", "0x" + Unk00.Hex);
            RelXml.ValueTag(sb, indent, "MusicType", MusicType.ToString());
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.ValueTag(sb, indent, "Unk06", Unk06.ToString());
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.ValueTag(sb, indent, "Unk11", Unk11.ToString());
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.ToString());
            RelXml.ValueTag(sb, indent, "Unk13", Unk13.ToString());
            RelXml.ValueTag(sb, indent, "Unk14", Unk14.ToString());
            RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.WriteItemArray(sb, Playlists, indent, "Playlists");
        }
        public override void ReadXml(XmlNode node)
        {
            Unk00 = Xml.GetChildUIntAttribute(node, "Unk00", "value");
            MusicType = (byte)Xml.GetChildUIntAttribute(node, "MusicType", "value");
            Unk01 = Xml.GetChildUIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildUIntAttribute(node, "Unk02", "value");
            Unk03 = (byte)Xml.GetChildUIntAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildUIntAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildUIntAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildUIntAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildUIntAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildUIntAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildUIntAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildUIntAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildUIntAttribute(node, "Unk11", "value");
            Unk12 = Xml.GetChildUIntAttribute(node, "Unk12", "value");
            Unk13 = Xml.GetChildUIntAttribute(node, "Unk13", "value");
            Unk14 = Xml.GetChildUIntAttribute(node, "Unk14", "value");
            Unk15 = Xml.GetChildUIntAttribute(node, "Unk15", "value");
            Unk16 = (ushort)Xml.GetChildUIntAttribute(node, "Unk16", "value");
            Playlists = XmlRel.ReadItemArray<Dat151HashPair>(node, "Playlists");
            PlaylistCount = (uint)(Playlists?.Length ?? 0);
        }
        public override MetaHash[] GetSoundHashes()
        {
            var list = new List<MetaHash>();
            if (Playlists != null)
            {
                foreach (var item in Playlists)
                {
                    list.Add(item.Hash1);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151RadioTrackList : Dat151RelData
    {
        public FlagsUint Unk00 { get; set; }
        public uint TrackCount { get; set; }
        public Dat151HashPair[] Tracks { get; set; }

        public Dat151RadioTrackList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.RadioTrackList;
            TypeID = (byte)Type;
        }
        public Dat151RadioTrackList(RelData d, BinaryReader br) : base(d, br)
        {
            Unk00 = br.ReadUInt32();
            TrackCount = br.ReadUInt32();
            Tracks = new Dat151HashPair[TrackCount];
            for (int i = 0; i < TrackCount; i++)
            {
                Tracks[i] = new Dat151HashPair(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk00);
            bw.Write(TrackCount);
            for (int i = 0; i < TrackCount; i++)
            {
                Tracks[i].Write(bw);
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk00", "0x" + Unk00.Hex);
            RelXml.WriteItemArray(sb, Tracks, indent, "Tracks");
        }
        public override void ReadXml(XmlNode node)
        {
            Unk00 = Xml.GetChildUIntAttribute(node, "Unk00", "value");
            Tracks = XmlRel.ReadItemArray<Dat151HashPair>(node, "Tracks");
            TrackCount = (uint)(Tracks?.Length ?? 0);
        }
        public override MetaHash[] GetSoundHashes()
        {
            var list = new List<MetaHash>();
            if (Tracks != null)
            {
                foreach (var item in Tracks)
                {
                    list.Add(item.Hash1);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151WeaponAudioItem : Dat151RelData
    {
        public MetaHash FallBackWeapon { get; set; }
        public uint AudioItemCount { get; set; }
        public Dat151WeaponAudioItemItem[] Weapons { get; set; }

        public Dat151WeaponAudioItem(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.WeaponAudioItem;
            TypeID = (byte)Type;
        }
        public Dat151WeaponAudioItem(RelData d, BinaryReader br) : base(d, br)
        {
            FallBackWeapon = br.ReadUInt32();
            AudioItemCount = br.ReadUInt32();

            Dat151WeaponAudioItemItem[] items = new Dat151WeaponAudioItemItem[AudioItemCount];
            for (int i = 0; i < AudioItemCount; i++)
            {
                items[i] = new Dat151WeaponAudioItemItem(br);
            }
            this.Weapons = items;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);
            bw.Write(FallBackWeapon);
            bw.Write(AudioItemCount);
            for (int i = 0; i < AudioItemCount; i++)
            {
                Weapons[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "FallBackWeapon", RelXml.HashString(FallBackWeapon));
            RelXml.WriteItemArray(sb, Weapons, indent, "Weapons");
        }
        public override void ReadXml(XmlNode node)
        {
            FallBackWeapon = XmlRel.GetHash(Xml.GetChildInnerText(node, "FallBackWeapon"));
            Weapons = XmlRel.ReadItemArray<Dat151WeaponAudioItemItem>(node, "Weapons");
            AudioItemCount = (uint)(Weapons?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            offsets.Add(0);
            for (uint i = 0; i < AudioItemCount; i++)
            {
                offsets.Add(12 + i * 8);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetCategoryHashes()
        {
            var list = new List<MetaHash>();
            if (Weapons != null)
            {
                foreach (var w in Weapons)
                {
                    list.Add(w.Category);//this doesn't seem to be an actual Category - eg player, player_backup
                }
            }
            return list.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            if (Weapons != null)
            {
                foreach (var w in Weapons)
                {
                    list.Add(w.Weapon);
                }
            }
            if ((Weapons?.Count(w => (w.Weapon == FallBackWeapon)) ?? 0) == 0)
            {
                list.Add(FallBackWeapon);
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public struct Dat151WeaponAudioItemItem : IMetaXmlItem
    {
        public MetaHash Category { get; set; }
        public MetaHash Weapon { get; set; }

        public Dat151WeaponAudioItemItem(BinaryReader br)
        {
            Category = br.ReadUInt32();
            Weapon = br.ReadUInt32();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Category);
            bw.Write(Weapon);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Category", RelXml.HashString(Category));
            RelXml.StringTag(sb, indent, "Weapon", RelXml.HashString(Weapon));
        }
        public void ReadXml(XmlNode node)
        {
            Category = XmlRel.GetHash(Xml.GetChildInnerText(node, "Category"));
            Weapon = XmlRel.GetHash(Xml.GetChildInnerText(node, "Weapon"));
        }
        public override string ToString()
        {
            return Category.ToString() + ": " + Weapon.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat151StartTrackAction : Dat151RelData
    {
        public FlagsUint Unk0 { get; set; }
        public int Unk1 { get; set; }
        public int Unk2 { get; set; }
        public MetaHash AudioTrack0 { get; set; }
        public MetaHash AudioTrack1 { get; set; }
        public float Unk3 { get; set; }
        public MetaHash Track { get; set; }
        public MetaHash Mood { get; set; }
        public float Unk5 { get; set; }
        public int Unk6 { get; set; }
        public int Unk7 { get; set; }
        public float Unk8 { get; set; }
        public int Unk9 { get; set; }
        public uint TracksCount { get; set; }
        public Dat151StartTrackActionItem[] Tracks { get; set; }


        public Dat151StartTrackAction(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.StartTrackAction;
            TypeID = (byte)Type;
        }
        public Dat151StartTrackAction(RelData d, BinaryReader br) : base(d, br)
        {
            Unk0 = br.ReadUInt32();
            Unk1 = br.ReadInt32();
            Unk2 = br.ReadInt32();
            AudioTrack0 = br.ReadUInt32();
            AudioTrack1 = br.ReadUInt32();
            Unk3 = br.ReadSingle();
            Track = br.ReadUInt32();
            Mood = br.ReadUInt32();
            Unk5 = br.ReadSingle();
            Unk6 = br.ReadInt32();
            Unk7 = br.ReadInt32();
            Unk8 = br.ReadSingle();
            Unk9 = br.ReadInt32();
            TracksCount = br.ReadUInt32();

            Dat151StartTrackActionItem[] items = new Dat151StartTrackActionItem[TracksCount];
            for (int i = 0; i < TracksCount; i++)
            {
                items[i] = new Dat151StartTrackActionItem(br);
            }
            this.Tracks = items;

            if (Unk1 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk0);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(AudioTrack0);
            bw.Write(AudioTrack1);
            bw.Write(Unk3);
            bw.Write(Track);
            bw.Write(Mood);
            bw.Write(Unk5);
            bw.Write(Unk6);
            bw.Write(Unk7);
            bw.Write(Unk8);
            bw.Write(Unk9);
            bw.Write(TracksCount);

            for (int i = 0; i < TracksCount; i++)
            {
                Tracks[i].Write(bw);
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk0", "0x" + Unk0.Hex);
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
            RelXml.ValueTag(sb, indent, "Unk2", Unk2.ToString());
            RelXml.StringTag(sb, indent, "AudioTrack0", RelXml.HashString(AudioTrack0));
            RelXml.StringTag(sb, indent, "AudioTrack1", RelXml.HashString(AudioTrack1));
            RelXml.ValueTag(sb, indent, "Unk3", FloatUtil.ToString(Unk3));
            RelXml.StringTag(sb, indent, "Track", RelXml.HashString(Track));
            RelXml.StringTag(sb, indent, "Mood", RelXml.HashString(Mood));
            RelXml.ValueTag(sb, indent, "Unk5", FloatUtil.ToString(Unk5));
            RelXml.ValueTag(sb, indent, "Unk6", Unk6.ToString());
            RelXml.ValueTag(sb, indent, "Unk7", Unk7.ToString());
            RelXml.ValueTag(sb, indent, "Unk8", FloatUtil.ToString(Unk8));
            RelXml.ValueTag(sb, indent, "Unk9", Unk9.ToString());
            RelXml.WriteItemArray(sb, Tracks, indent, "Tracks");
        }
        public override void ReadXml(XmlNode node)
        {
            Unk0 = Xml.GetChildUIntAttribute(node, "Unk0", "value");
            Unk1 = Xml.GetChildIntAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildIntAttribute(node, "Unk2", "value");
            AudioTrack0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack0"));
            AudioTrack1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack1"));
            Unk3 = Xml.GetChildFloatAttribute(node, "Unk3", "value");
            Track = XmlRel.GetHash(Xml.GetChildInnerText(node, "Track"));
            Mood = XmlRel.GetHash(Xml.GetChildInnerText(node, "Mood"));
            Unk5 = Xml.GetChildFloatAttribute(node, "Unk5", "value");
            Unk6 = Xml.GetChildIntAttribute(node, "Unk6", "value");
            Unk7 = Xml.GetChildIntAttribute(node, "Unk7", "value");
            Unk8 = Xml.GetChildFloatAttribute(node, "Unk8", "value");
            Unk9 = Xml.GetChildIntAttribute(node, "Unk9", "value");
            Tracks = XmlRel.ReadItemArray<Dat151StartTrackActionItem>(node, "Tracks");
            TracksCount = (uint)(Tracks?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 12, 16, 28 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { AudioTrack0, AudioTrack1, Mood };
        }
        public override MetaHash[] GetSoundHashes()
        {
            var list = new List<MetaHash>();
            list.Add(Track);
            if (Tracks != null)
            {
                foreach (var t in Tracks)
                {
                    list.Add(t.Track);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public struct Dat151StartTrackActionItem : IMetaXmlItem
    {
        public MetaHash Track { get; set; }
        public FlagsUint Flags { get; set; }

        public Dat151StartTrackActionItem(BinaryReader br)
        {
            Track = br.ReadUInt32();
            Flags = br.ReadUInt32();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Track);
            bw.Write(Flags);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Track", RelXml.HashString(Track));
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
        }
        public void ReadXml(XmlNode node)
        {
            Track = XmlRel.GetHash(Xml.GetChildInnerText(node, "Track"));
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
        }
        public override string ToString()
        {
            return Track.ToString() + ": " + Flags.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat151StopTrackAction : Dat151RelData
    {
        public FlagsUint Unk0 { get; set; }
        public int Unk1 { get; set; }
        public int Unk2 { get; set; }
        public MetaHash AudioTrack0 { get; set; }
        public MetaHash AudioTrack1 { get; set; }
        public float Unk3 { get; set; }
        public int Unk4 { get; set; }

        public Dat151StopTrackAction(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.StopTrackAction;
            TypeID = (byte)Type;
        }
        public Dat151StopTrackAction(RelData d, BinaryReader br) : base(d, br)
        {
            Unk0 = br.ReadUInt32();
            Unk1 = br.ReadInt32();
            Unk2 = br.ReadInt32();
            AudioTrack0 = br.ReadUInt32();
            AudioTrack1 = br.ReadUInt32();
            Unk3 = br.ReadSingle();
            Unk4 = br.ReadInt32();

            if (Unk1 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk0);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(AudioTrack0);
            bw.Write(AudioTrack1);
            bw.Write(Unk3);
            bw.Write(Unk4);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk0", "0x" + Unk0.Hex);
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
            RelXml.ValueTag(sb, indent, "Unk2", Unk2.ToString());
            RelXml.StringTag(sb, indent, "AudioTrack0", RelXml.HashString(AudioTrack0));
            RelXml.StringTag(sb, indent, "AudioTrack1", RelXml.HashString(AudioTrack1));
            RelXml.ValueTag(sb, indent, "Unk3", FloatUtil.ToString(Unk3));
            RelXml.ValueTag(sb, indent, "Unk4", Unk4.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk0 = Xml.GetChildUIntAttribute(node, "Unk0", "value");
            Unk1 = Xml.GetChildIntAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildIntAttribute(node, "Unk2", "value");
            AudioTrack0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack0"));
            AudioTrack1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack1"));
            Unk3 = Xml.GetChildFloatAttribute(node, "Unk3", "value");
            Unk4 = Xml.GetChildIntAttribute(node, "Unk4", "value");
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 12, 16 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { AudioTrack0, AudioTrack1 };
        }
    }
    [TC(typeof(EXP))] public class Dat151MoodItem : IMetaXmlItem
    {
        public MetaHash StemMix { get; set; }
        public MetaHash StopAction { get; set; }
        public float Unk1 { get; set; }
        public float Unk2 { get; set; }
        public float Unk3 { get; set; }
        public float Unk4 { get; set; }
        public MetaHash Beat { get; set; }//unk69 (beat change?)
        public MetaHash Unk5 { get; set; }

        public override string ToString()
        {
            return StemMix.ToString();
        }

        public Dat151MoodItem()
        {
        }
        public Dat151MoodItem(BinaryReader br)
        {
            StemMix = br.ReadUInt32();
            StopAction = br.ReadUInt32();
            Unk1 = br.ReadSingle();
            Unk2 = br.ReadSingle();
            Unk3 = br.ReadSingle();
            Unk4 = br.ReadSingle();
            Beat = br.ReadUInt32();
            Unk5 = br.ReadUInt32();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(StemMix);
            bw.Write(StopAction);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(Unk3);
            bw.Write(Unk4);
            bw.Write(Beat);
            bw.Write(Unk5);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "StemMix", RelXml.HashString(StemMix));
            RelXml.StringTag(sb, indent, "StopAction", RelXml.HashString(StopAction));
            RelXml.ValueTag(sb, indent, "Unk1", FloatUtil.ToString(Unk1));
            RelXml.ValueTag(sb, indent, "Unk2", FloatUtil.ToString(Unk2));
            RelXml.ValueTag(sb, indent, "Unk3", FloatUtil.ToString(Unk3));
            RelXml.ValueTag(sb, indent, "Unk4", FloatUtil.ToString(Unk4));
            RelXml.StringTag(sb, indent, "Beat", RelXml.HashString(Beat));
            RelXml.StringTag(sb, indent, "Unk5", RelXml.HashString(Unk5));
        }
        public void ReadXml(XmlNode node)
        {
            StemMix = XmlRel.GetHash(Xml.GetChildInnerText(node, "StemMix"));
            StopAction = XmlRel.GetHash(Xml.GetChildInnerText(node, "StopAction"));
            Unk1 = Xml.GetChildFloatAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildFloatAttribute(node, "Unk2", "value");
            Unk3 = Xml.GetChildFloatAttribute(node, "Unk3", "value");
            Unk4 = Xml.GetChildFloatAttribute(node, "Unk4", "value");
            Beat = XmlRel.GetHash(Xml.GetChildInnerText(node, "Beat"));
            Unk5 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk5"));
        }
    }
    [TC(typeof(EXP))] public class Dat151Mood : Dat151RelData
    {
        public FlagsUint Unk0 { get; set; }
        public ushort Unk1 { get; set; }
        public ushort Unk2 { get; set; }
        public float Unk3 { get; set; }
        public uint MoodItemCount { get; set; }
        public Dat151MoodItem[] MoodItems { get; set; }

        public Dat151Mood(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Mood;
            TypeID = (byte)Type;
        }
        public Dat151Mood(RelData d, BinaryReader br) : base(d, br)
        {
            Unk0 = br.ReadUInt32();
            Unk1 = br.ReadUInt16();
            Unk2 = br.ReadUInt16();
            Unk3 = br.ReadSingle();
            MoodItemCount = br.ReadUInt32();
            var items = new Dat151MoodItem[MoodItemCount];
            for (int i = 0; i < MoodItemCount; i++)
            {
                items[i] = new Dat151MoodItem(br);
            }
            MoodItems = items;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk0);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(Unk3);
            bw.Write(MoodItemCount);
            for (int i = 0; i < MoodItemCount; i++)
            {
                MoodItems[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk0", "0x" + Unk0.Hex);
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
            RelXml.ValueTag(sb, indent, "Unk2", Unk2.ToString());
            RelXml.ValueTag(sb, indent, "Unk3", FloatUtil.ToString(Unk3));
            RelXml.WriteItemArray(sb, MoodItems, indent, "MoodItems");
        }
        public override void ReadXml(XmlNode node)
        {
            Unk0 = Xml.GetChildUIntAttribute(node, "Unk0", "value");
            Unk1 = (ushort)Xml.GetChildUIntAttribute(node, "Unk1", "value");
            Unk2 = (ushort)Xml.GetChildUIntAttribute(node, "Unk2", "value");
            Unk3 = Xml.GetChildFloatAttribute(node, "Unk3", "value");
            MoodItems = XmlRel.ReadItemArray<Dat151MoodItem>(node, "MoodItems");
            MoodItemCount = (uint)(MoodItems?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < MoodItemCount; i++)
            {
                var offs = 16 + i * 32; //offsets for each mood item's subitems
                offsets.Add(offs);
                offsets.Add(offs + 4);
                offsets.Add(offs + 24);
                offsets.Add(offs + 28);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            if (MoodItems != null)
            {
                foreach (var item in MoodItems)
                {
                    list.Add(item.StemMix);
                    list.Add(item.StopAction);
                    list.Add(item.Beat);
                    list.Add(item.Unk5);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151SetMoodAction : Dat151RelData
    {
        public FlagsUint Unk0 { get; set; }
        public int Unk1 { get; set; }
        public int Unk2 { get; set; }
        public MetaHash AudioTrack0 { get; set; }//type unk70
        public MetaHash AudioTrack1 { get; set; }//not used?
        public float Unk3 { get; set; }
        public MetaHash Mood { get; set; }
        public float Unk4 { get; set; }
        public int Unk5 { get; set; }
        public int Unk6 { get; set; }

        public Dat151SetMoodAction(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.SetMoodAction;
            TypeID = (byte)Type;
        }
        public Dat151SetMoodAction(RelData d, BinaryReader br) : base(d, br)
        {
            Unk0 = br.ReadUInt32();
            Unk1 = br.ReadInt32();
            Unk2 = br.ReadInt32();
            AudioTrack0 = br.ReadUInt32();
            AudioTrack1 = br.ReadUInt32();
            Unk3 = br.ReadSingle();
            Mood = br.ReadUInt32();
            Unk4 = br.ReadSingle();
            Unk5 = br.ReadInt32();
            Unk6 = br.ReadInt32();

            if (Unk1 != 0)
            { }
            if (this.AudioTrack0 != 0)
            { }
            if (this.AudioTrack1 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk0);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(AudioTrack0);
            bw.Write(AudioTrack1);
            bw.Write(Unk3);
            bw.Write(Mood);
            bw.Write(Unk4);
            bw.Write(Unk5);
            bw.Write(Unk6);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk0", "0x" + Unk0.Hex);
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
            RelXml.ValueTag(sb, indent, "Unk2", Unk2.ToString());
            RelXml.StringTag(sb, indent, "AudioTrack0", RelXml.HashString(AudioTrack0));
            RelXml.StringTag(sb, indent, "AudioTrack1", RelXml.HashString(AudioTrack1));
            RelXml.ValueTag(sb, indent, "Unk3", FloatUtil.ToString(Unk3));
            RelXml.StringTag(sb, indent, "Mood", RelXml.HashString(Mood));
            RelXml.ValueTag(sb, indent, "Unk4", FloatUtil.ToString(Unk4));
            RelXml.ValueTag(sb, indent, "Unk5", Unk5.ToString());
            RelXml.ValueTag(sb, indent, "Unk6", Unk6.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk0 = Xml.GetChildUIntAttribute(node, "Unk0", "value");
            Unk1 = Xml.GetChildIntAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildIntAttribute(node, "Unk2", "value");
            AudioTrack0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack0"));
            AudioTrack1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack1"));
            Unk3 = Xml.GetChildFloatAttribute(node, "Unk3", "value");
            Mood = XmlRel.GetHash(Xml.GetChildInnerText(node, "Mood"));
            Unk4 = Xml.GetChildFloatAttribute(node, "Unk4", "value");
            Unk5 = Xml.GetChildIntAttribute(node, "Unk5", "value");
            Unk6 = Xml.GetChildIntAttribute(node, "Unk6", "value");
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 12, 16, 24 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { AudioTrack0, AudioTrack1, Mood };
        }
    }
    [TC(typeof(EXP))] public class Dat151PlayerAction : Dat151RelData
    {
        public uint AudioTrackCount { get; set; }
        public MetaHash[] AudioTracks { get; set; }

        public Dat151PlayerAction(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.PlayerAction;
            TypeID = (byte)Type;
        }
        public Dat151PlayerAction(RelData d, BinaryReader br) : base(d, br)
        {
            AudioTrackCount = br.ReadUInt32();
            var tracks = new MetaHash[AudioTrackCount];
            for (int i = 0; i < AudioTrackCount; i++)
            {
                tracks[i] = br.ReadUInt32();
            }
            AudioTracks = tracks;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(AudioTrackCount);
            for (int i = 0; i < AudioTrackCount; i++)
            {
                bw.Write(AudioTracks[i]);
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteHashItemArray(sb, AudioTracks, indent, "ChildSounds");
        }
        public override void ReadXml(XmlNode node)
        {
            AudioTracks = XmlRel.ReadHashItemArray(node, "ChildSounds");
            AudioTrackCount = (uint)(AudioTracks?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < AudioTrackCount; i++)
            {
                var offs = 4 + i * 4; //offsets for each audio track
                offsets.Add(offs);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            return AudioTracks;
        }
    }
    [TC(typeof(EXP))] public class Dat151StartOneShotAction : Dat151RelData
    {
        public FlagsUint Unk0 { get; set; }
        public int Unk1 { get; set; }
        public int Unk2 { get; set; }
        public MetaHash AudioTrack0 { get; set; }//type unk70
        public MetaHash AudioTrack1 { get; set; }//not used
        public float Unk3 { get; set; }
        public MetaHash Sound { get; set; }
        public int Unk5 { get; set; }
        public int Unk6 { get; set; }
        public int Unk7 { get; set; }
        public int Unk8 { get; set; }

        public Dat151StartOneShotAction(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.StartOneShotAction;
            TypeID = (byte)Type;
        }
        public Dat151StartOneShotAction(RelData d, BinaryReader br) : base(d, br)
        {
            Unk0 = br.ReadUInt32();
            Unk1 = br.ReadInt32();
            Unk2 = br.ReadInt32();
            AudioTrack0 = br.ReadUInt32();
            AudioTrack1 = br.ReadUInt32();
            Unk3 = br.ReadSingle();
            Sound = br.ReadUInt32();
            Unk5 = br.ReadInt32();
            Unk6 = br.ReadInt32();
            Unk7 = br.ReadInt32();
            Unk8 = br.ReadInt32();

            if (Unk1 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk0);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(AudioTrack0);
            bw.Write(AudioTrack1);
            bw.Write(Unk3);
            bw.Write(Sound);
            bw.Write(Unk5);
            bw.Write(Unk6);
            bw.Write(Unk7);
            bw.Write(Unk8);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk0", "0x" + Unk0.Hex);
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
            RelXml.ValueTag(sb, indent, "Unk2", Unk2.ToString());
            RelXml.StringTag(sb, indent, "AudioTrack0", RelXml.HashString(AudioTrack0));
            RelXml.StringTag(sb, indent, "AudioTrack1", RelXml.HashString(AudioTrack1));
            RelXml.ValueTag(sb, indent, "Unk3", FloatUtil.ToString(Unk3));
            RelXml.StringTag(sb, indent, "Sound", RelXml.HashString(Sound));
            RelXml.ValueTag(sb, indent, "Unk5", Unk5.ToString());
            RelXml.ValueTag(sb, indent, "Unk6", Unk6.ToString());
            RelXml.ValueTag(sb, indent, "Unk7", Unk7.ToString());
            RelXml.ValueTag(sb, indent, "Unk8", Unk8.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk0 = Xml.GetChildUIntAttribute(node, "Unk0", "value");
            Unk1 = Xml.GetChildIntAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildIntAttribute(node, "Unk2", "value");
            AudioTrack0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack0"));
            AudioTrack1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack1"));
            Unk3 = Xml.GetChildFloatAttribute(node, "Unk3", "value");
            Sound = XmlRel.GetHash(Xml.GetChildInnerText(node, "Sound"));
            Unk5 = Xml.GetChildIntAttribute(node, "Unk5", "value");
            Unk6 = Xml.GetChildIntAttribute(node, "Unk6", "value");
            Unk7 = Xml.GetChildIntAttribute(node, "Unk7", "value");
            Unk8 = Xml.GetChildIntAttribute(node, "Unk8", "value");
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 12, 16 };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Sound };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { AudioTrack0, AudioTrack1 };
        }
    }
    [TC(typeof(EXP))] public class Dat151StopOneShotAction : Dat151RelData
    {
        public FlagsUint Unk0 { get; set; }
        public int Unk1 { get; set; }
        public int Unk2 { get; set; }
        public MetaHash AudioTrack0 { get; set; }//not used
        public MetaHash AudioTrack1 { get; set; }//not used
        public int Unk3 { get; set; }

        public Dat151StopOneShotAction(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.StopOneShotAction;
            TypeID = (byte)Type;
        }
        public Dat151StopOneShotAction(RelData d, BinaryReader br) : base(d, br)
        {
            Unk0 = br.ReadUInt32();
            Unk1 = br.ReadInt32();
            Unk2 = br.ReadInt32();
            AudioTrack0 = br.ReadUInt32();
            AudioTrack1 = br.ReadUInt32();
            Unk3 = br.ReadInt32();

            if (Unk1 != 0)
            { }
            if (Unk2 != 0)
            { }
            if (Unk3 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk0);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(AudioTrack0);
            bw.Write(AudioTrack1);
            bw.Write(Unk3);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk0", "0x" + Unk0.Hex);
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
            RelXml.ValueTag(sb, indent, "Unk2", Unk2.ToString());
            RelXml.StringTag(sb, indent, "AudioTrack0", RelXml.HashString(AudioTrack0));
            RelXml.StringTag(sb, indent, "AudioTrack1", RelXml.HashString(AudioTrack1));
            RelXml.ValueTag(sb, indent, "Unk3", Unk3.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk0 = Xml.GetChildUIntAttribute(node, "Unk0", "value");
            Unk1 = Xml.GetChildIntAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildIntAttribute(node, "Unk2", "value");
            AudioTrack0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack0"));
            AudioTrack1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack1"));
            Unk3 = Xml.GetChildIntAttribute(node, "Unk3", "value");
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 12, 16 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { AudioTrack0, AudioTrack1 };
        }
    }
    [TC(typeof(EXP))] public class Dat151FadeInRadioAction : Dat151RelData
    {
        public FlagsUint Unk0 { get; set; }
        public int Unk1 { get; set; }
        public int Unk2 { get; set; }
        public MetaHash AudioTrack0 { get; set; }//not used
        public MetaHash AudioTrack1 { get; set; }//not used
        public float Unk3 { get; set; }
        public float Unk4 { get; set; }

        public Dat151FadeInRadioAction(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.FadeInRadioAction;
            TypeID = (byte)Type;
        }
        public Dat151FadeInRadioAction(RelData d, BinaryReader br) : base(d, br)
        {
            Unk0 = br.ReadUInt32();
            Unk1 = br.ReadInt32();
            Unk2 = br.ReadInt32();
            AudioTrack0 = br.ReadUInt32();
            AudioTrack1 = br.ReadUInt32();
            Unk3 = br.ReadSingle();
            Unk4 = br.ReadSingle();

            if (Unk1 != 0)
            { }
            if (Unk2 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk0);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(AudioTrack0);
            bw.Write(AudioTrack1);
            bw.Write(Unk3);
            bw.Write(Unk4);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk0", "0x" + Unk0.Hex);
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
            RelXml.ValueTag(sb, indent, "Unk2", Unk2.ToString());
            RelXml.StringTag(sb, indent, "AudioTrack0", RelXml.HashString(AudioTrack0));
            RelXml.StringTag(sb, indent, "AudioTrack1", RelXml.HashString(AudioTrack1));
            RelXml.ValueTag(sb, indent, "Unk3", FloatUtil.ToString(Unk3));
            RelXml.ValueTag(sb, indent, "Unk4", FloatUtil.ToString(Unk4));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk0 = Xml.GetChildUIntAttribute(node, "Unk0", "value");
            Unk1 = Xml.GetChildIntAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildIntAttribute(node, "Unk2", "value");
            AudioTrack0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack0"));
            AudioTrack1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack1"));
            Unk3 = Xml.GetChildFloatAttribute(node, "Unk3", "value");
            Unk4 = Xml.GetChildFloatAttribute(node, "Unk4", "value");
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 12, 16 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { AudioTrack0, AudioTrack1 };
        }
    }
    [TC(typeof(EXP))] public class Dat151FadeOutRadioAction : Dat151RelData
    {
        public FlagsUint Unk0 { get; set; }
        public int Unk1 { get; set; }
        public int Unk2 { get; set; }
        public MetaHash AudioTrack0 { get; set; }//not used
        public MetaHash AudioTrack1 { get; set; }//not used
        public float Unk3 { get; set; }
        public float Unk4 { get; set; }

        public Dat151FadeOutRadioAction(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.FadeOutRadioAction;
            TypeID = (byte)Type;
        }
        public Dat151FadeOutRadioAction(RelData d, BinaryReader br) : base(d, br)
        {
            Unk0 = br.ReadUInt32();
            Unk1 = br.ReadInt32();
            Unk2 = br.ReadInt32();
            AudioTrack0 = br.ReadUInt32();
            AudioTrack1 = br.ReadUInt32();
            Unk3 = br.ReadSingle();
            Unk4 = br.ReadSingle();

            if (Unk1 != 0)
            { }
            if (Unk2 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk0);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(AudioTrack0);
            bw.Write(AudioTrack1);
            bw.Write(Unk3);
            bw.Write(Unk4);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk0", "0x" + Unk0.Hex);
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
            RelXml.ValueTag(sb, indent, "Unk2", Unk2.ToString());
            RelXml.StringTag(sb, indent, "AudioTrack0", RelXml.HashString(AudioTrack0));
            RelXml.StringTag(sb, indent, "AudioTrack1", RelXml.HashString(AudioTrack1));
            RelXml.ValueTag(sb, indent, "Unk3", FloatUtil.ToString(Unk3));
            RelXml.ValueTag(sb, indent, "Unk4", FloatUtil.ToString(Unk4));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk0 = Xml.GetChildUIntAttribute(node, "Unk0", "value");
            Unk1 = Xml.GetChildIntAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildIntAttribute(node, "Unk2", "value");
            AudioTrack0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack0"));
            AudioTrack1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack1"));
            Unk3 = Xml.GetChildFloatAttribute(node, "Unk3", "value");
            Unk4 = Xml.GetChildFloatAttribute(node, "Unk4", "value");
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 12, 16 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { AudioTrack0, AudioTrack1 };
        }
    }
    [TC(typeof(EXP))] public class Dat151Mod : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public int Unk01 { get; set; }
        public int Unk02 { get; set; }
        public int Unk03 { get; set; }
        public MetaHash Unk04 { get; set; }
        public MetaHash Unk05 { get; set; }
        public MetaHash Unk06 { get; set; }
        public MetaHash Unk07 { get; set; }//sound set
        public MetaHash Unk08 { get; set; }
        public float Unk09 { get; set; }
        public float Unk10 { get; set; }
        public MetaHash Unk11 { get; set; }
        public MetaHash Unk12 { get; set; }
        public MetaHash Unk13 { get; set; }
        public MetaHash Unk14 { get; set; }
        public byte Unk15 { get; set; }
        public byte AudioTracks1Count { get; set; }
        public byte Unk16 { get; set; }
        public byte Unk17 { get; set; }
        public MetaHash AudioTrack0 { get; set; }//not used
        public Dat151HashPair[] AudioTracks1 { get; set; }//AudioMaterial pairs
        public uint AudioTracks2Count { get; set; }
        public MetaHash[] AudioTracks2 { get; set; }//more mod objects


        public Dat151Mod(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Mod;
            TypeID = (byte)Type;
        }
        public Dat151Mod(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Unk01 = br.ReadInt32();
            Unk02 = br.ReadInt32();
            Unk03 = br.ReadInt32();
            Unk04 = br.ReadUInt32();
            Unk05 = br.ReadUInt32();
            Unk06 = br.ReadUInt32();
            Unk07 = br.ReadUInt32();
            Unk08 = br.ReadUInt32();
            Unk09 = br.ReadSingle();
            Unk10 = br.ReadSingle();
            Unk11 = br.ReadUInt32();
            Unk12 = br.ReadUInt32();
            Unk13 = br.ReadUInt32();
            Unk14 = br.ReadUInt32();
            Unk15 = br.ReadByte();
            AudioTracks1Count = br.ReadByte();
            Unk16 = br.ReadByte();
            Unk17 = br.ReadByte();

            //byte tc1 = (byte)((Unk15) & 0xFF);
            //byte tc2 = (byte)((Unk15 >> 8) & 0xFF);
            //byte tc3 = (byte)((Unk15 >> 16) & 0xFF);
            //byte tc4 = (byte)((Unk15 >> 24) & 0xFF);

            switch (Unk15)//not sure what this is
            {
                case 0:
                case 1:
                case 2:
                case 3:
                case 4:
                    break;
                default:
                    break;
            }


            if (AudioTracks1Count == 0)
            {
                AudioTrack0 = br.ReadUInt32();
                //AudioTracks2 = new MetaHash[] { AudioTrack0 };
            }
            else //if (AudioTracks1Count > 0)
            {
                var tracks1 = new Dat151HashPair[AudioTracks1Count];
                for (int i = 0; i < AudioTracks1Count; i++)
                {
                    tracks1[i] = new Dat151HashPair(br);
                }
                AudioTracks1 = tracks1;

                AudioTracks2Count = br.ReadUInt32();

                var tracks2 = new MetaHash[AudioTracks2Count];
                for (int i = 0; i < AudioTracks2Count; i++)
                {
                    tracks2[i] = br.ReadUInt32();
                }
                AudioTracks2 = tracks2;
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(AudioTracks1Count);
            bw.Write(Unk16);
            bw.Write(Unk17);


            if (AudioTracks1Count == 0)
            {
                bw.Write(AudioTrack0);//hrmm
            }
            else //if (AudioTracks1Count > 0)
            {
                for (int i = 0; i < AudioTracks1Count; i++)
                {
                    AudioTracks1[i].Write(bw);
                }
                bw.Write(AudioTracks2Count);
                for (int i = 0; i < AudioTracks2Count; i++)
                {
                    bw.Write(AudioTracks2[i]);
                }
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.ValueTag(sb, indent, "Unk09", FloatUtil.ToString(Unk09));
            RelXml.ValueTag(sb, indent, "Unk10", FloatUtil.ToString(Unk10));
            RelXml.StringTag(sb, indent, "Unk11", RelXml.HashString(Unk11));
            RelXml.StringTag(sb, indent, "Unk12", RelXml.HashString(Unk12));
            RelXml.StringTag(sb, indent, "Unk13", RelXml.HashString(Unk13));
            RelXml.StringTag(sb, indent, "Unk14", RelXml.HashString(Unk14));
            RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.ValueTag(sb, indent, "Unk17", Unk17.ToString());
            if (AudioTracks1Count == 0)
            {
                RelXml.StringTag(sb, indent, "AudioTrack0", RelXml.HashString(AudioTrack0));
            }
            else
            {
                RelXml.WriteItemArray(sb, AudioTracks1, indent, "AudioTracks1");
                RelXml.WriteHashItemArray(sb, AudioTracks2, indent, "AudioTracks2");
            }
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = Xml.GetChildIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildIntAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildIntAttribute(node, "Unk03", "value");
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = Xml.GetChildFloatAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildFloatAttribute(node, "Unk10", "value");
            Unk11 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk11"));
            Unk12 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk12"));
            Unk13 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk13"));
            Unk14 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk14"));
            Unk15 = (byte)Xml.GetChildUIntAttribute(node, "Unk15", "value");
            Unk16 = (byte)Xml.GetChildUIntAttribute(node, "Unk16", "value");
            Unk17 = (byte)Xml.GetChildUIntAttribute(node, "Unk17", "value");
            AudioTrack0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack0"));
            AudioTracks1 = XmlRel.ReadItemArray<Dat151HashPair>(node, "AudioTracks1");
            AudioTracks1Count = (byte)(AudioTracks1?.Length ?? 0);
            AudioTracks2 = XmlRel.ReadHashItemArray(node, "AudioTracks2");
            AudioTracks2Count = (uint)(AudioTracks2?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            uint offs = 64;
            if (AudioTracks1Count == 0)
            {
            }
            else //if (AudioTracks1Count > 0)
            {
                for (uint i = 0; i < AudioTracks1Count; i++)
                {
                    offsets.Add(offs);
                    offsets.Add(offs + 4);
                    offs += 8;
                }
                offs += 4;
                for (uint i = 0; i < AudioTracks2Count; i++)
                {
                    offsets.Add(offs);
                    offs += 4;
                }
            }

            return offsets.ToArray();
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk04, Unk05, Unk06, Unk07, Unk08, Unk11, Unk12, Unk13, Unk14 };
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            list.Add(AudioTrack0);
            if (AudioTracks1 != null)
            {
                foreach (var item in AudioTracks1)
                {
                    list.Add(item.Hash0);
                    list.Add(item.Hash1);
                }
            }
            if (AudioTracks2 != null)
            {
                list.AddRange(AudioTracks2);
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151DoorModel : Dat151RelData
    {
        public MetaHash Door { get; set; }

        public Dat151DoorModel(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.DoorModel;
            TypeID = (byte)Type;
        }
        public Dat151DoorModel(RelData d, BinaryReader br) : base(d, br)
        {
            Door = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Door);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Door", RelXml.HashString(Door));
        }
        public override void ReadXml(XmlNode node)
        {
            Door = XmlRel.GetHash(Xml.GetChildInnerText(node, "Door"));
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 0 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { Door };
        }
    }
    [TC(typeof(EXP))] public class Dat151AudioMaterial : Dat151RelData
    {
        public FlagsUint Unk00 { get; set; }
        public MetaHash Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }
        public MetaHash Unk04 { get; set; }
        public MetaHash Unk05 { get; set; }
        public MetaHash Unk06 { get; set; }
        public MetaHash Unk07 { get; set; }
        public MetaHash Unk08 { get; set; }
        public MetaHash Unk09 { get; set; }
        public MetaHash Unk10 { get; set; }
        public MetaHash Unk11 { get; set; }
        public MetaHash Unk12 { get; set; }
        public MetaHash Unk13 { get; set; }
        public MetaHash Unk14 { get; set; }
        public int Unk15 { get; set; }
        public int Unk16 { get; set; }
        public int Unk17 { get; set; }
        public int Unk18 { get; set; }
        public float Unk19 { get; set; }
        public int Unk20 { get; set; }
        public float Unk21 { get; set; }
        public float Unk22 { get; set; }
        public float Unk23 { get; set; }
        public float Unk24 { get; set; }
        public float Unk25 { get; set; }
        public float Unk26 { get; set; }
        public int Unk27 { get; set; }
        public MetaHash Unk28 { get; set; }
        public float Unk29 { get; set; }
        public float Unk30 { get; set; }
        public MetaHash Footsteps { get; set; }
        public int Unk31 { get; set; }
        public MetaHash Unk32 { get; set; }
        public MetaHash AnimalFootsteps { get; set; }
        public MetaHash AudioTrack2 { get; set; }
        public MetaHash Unk33 { get; set; }
        public MetaHash Unk34 { get; set; }
        public MetaHash Unk35 { get; set; }
        public MetaHash Unk36 { get; set; }
        public MetaHash Unk37 { get; set; }
        public MetaHash Unk38 { get; set; }
        public MetaHash Unk39 { get; set; }
        public MetaHash Unk40 { get; set; }
        public MetaHash Unk41 { get; set; }
        public MetaHash Unk42 { get; set; }
        public MetaHash Unk43 { get; set; }
        public MetaHash Unk44 { get; set; }
        public MetaHash Unk45 { get; set; }
        public MetaHash Unk46 { get; set; }
        public MetaHash Unk47 { get; set; }
        public MetaHash Unk48 { get; set; }
        public MetaHash Unk49 { get; set; }
        public MetaHash Unk50 { get; set; }
        public MetaHash Unk51 { get; set; }
        public MetaHash Unk52 { get; set; }
        public MetaHash Unk53 { get; set; }
        public MetaHash Unk54 { get; set; }
        public float Unk55 { get; set; }
        public MetaHash Unk56 { get; set; }
        public MetaHash Unk57 { get; set; }
        public int Unk58 { get; set; }
        public int Unk59 { get; set; }
        public float Unk60 { get; set; }
        public int Unk61 { get; set; }
        public int Unk62 { get; set; }
        public MetaHash Unk63 { get; set; }
        public MetaHash Unk64 { get; set; }
        public MetaHash Unk65 { get; set; }
        public int Unk66 { get; set; }
        public MetaHash Unk67 { get; set; }
        public MetaHash Unk68 { get; set; }
        public MetaHash Unk69 { get; set; }
        public MetaHash Unk70 { get; set; }
        public MetaHash Unk71 { get; set; }
        public int Unk72 { get; set; }
        public MetaHash Unk73 { get; set; }
        public MetaHash Unk74 { get; set; }
        public MetaHash Unk75 { get; set; }
        public MetaHash Unk76 { get; set; }
        public float Unk77 { get; set; }
        public MetaHash Unk78 { get; set; }//another AudioMaterial
        public MetaHash Unk79 { get; set; }//self reference
        public MetaHash Unk80 { get; set; }
        public MetaHash Unk81 { get; set; }
        public MetaHash Unk82 { get; set; }
        public MetaHash Unk83 { get; set; }
        public MetaHash Unk84 { get; set; }
        public int Unk85 { get; set; }
        public MetaHash Unk86 { get; set; }
        public int Unk87 { get; set; }
        public MetaHash Unk88 { get; set; }
        public int Unk89 { get; set; }

        public Dat151AudioMaterial(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.AudioMaterial;
            TypeID = (byte)Type;
        }
        public Dat151AudioMaterial(RelData d, BinaryReader br) : base(d, br)
        {
            Unk00 = br.ReadUInt32();
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadUInt32();
            Unk03 = br.ReadUInt32();
            Unk04 = br.ReadUInt32();
            Unk05 = br.ReadUInt32();
            Unk06 = br.ReadUInt32();
            Unk07 = br.ReadUInt32();
            Unk08 = br.ReadUInt32();
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadUInt32();
            Unk11 = br.ReadUInt32();
            Unk12 = br.ReadUInt32();
            Unk13 = br.ReadUInt32();
            Unk14 = br.ReadUInt32();
            Unk15 = br.ReadInt32();
            Unk16 = br.ReadInt32();
            Unk17 = br.ReadInt32();
            Unk18 = br.ReadInt32();
            Unk19 = br.ReadSingle();
            Unk20 = br.ReadInt32();
            Unk21 = br.ReadSingle();
            Unk22 = br.ReadSingle();
            Unk23 = br.ReadSingle();
            Unk24 = br.ReadSingle();
            Unk25 = br.ReadSingle();
            Unk26 = br.ReadSingle();
            Unk27 = br.ReadInt32();
            Unk28 = br.ReadUInt32();
            Unk29 = br.ReadSingle();
            Unk30 = br.ReadSingle();
            Footsteps = br.ReadUInt32();
            Unk31 = br.ReadInt32();
            Unk32 = br.ReadUInt32();
            AnimalFootsteps = br.ReadUInt32();
            AudioTrack2 = br.ReadUInt32();
            Unk33 = br.ReadUInt32();
            Unk34 = br.ReadUInt32();
            Unk35 = br.ReadUInt32();
            Unk36 = br.ReadUInt32();
            Unk37 = br.ReadUInt32();
            Unk38 = br.ReadUInt32();
            Unk39 = br.ReadUInt32();
            Unk40 = br.ReadUInt32();
            Unk41 = br.ReadUInt32();
            Unk42 = br.ReadUInt32();
            Unk43 = br.ReadUInt32();
            Unk44 = br.ReadUInt32();
            Unk45 = br.ReadUInt32();
            Unk46 = br.ReadUInt32();
            Unk47 = br.ReadUInt32();
            Unk48 = br.ReadUInt32();
            Unk49 = br.ReadUInt32();
            Unk50 = br.ReadUInt32();
            Unk51 = br.ReadUInt32();
            Unk52 = br.ReadUInt32();
            Unk53 = br.ReadUInt32();
            Unk54 = br.ReadUInt32();
            Unk55 = br.ReadSingle();
            Unk56 = br.ReadUInt32();
            Unk57 = br.ReadUInt32();
            Unk58 = br.ReadInt32();
            Unk59 = br.ReadInt32();
            Unk60 = br.ReadSingle();
            Unk61 = br.ReadInt32();
            Unk62 = br.ReadInt32();
            Unk63 = br.ReadUInt32();
            Unk64 = br.ReadUInt32();
            Unk65 = br.ReadUInt32();
            Unk66 = br.ReadInt32();
            Unk67 = br.ReadUInt32();
            Unk68 = br.ReadUInt32();
            Unk69 = br.ReadUInt32();
            Unk70 = br.ReadUInt32();
            Unk71 = br.ReadUInt32();
            Unk72 = br.ReadInt32();
            Unk73 = br.ReadUInt32();
            Unk74 = br.ReadUInt32();
            Unk75 = br.ReadUInt32();
            Unk76 = br.ReadUInt32();
            Unk77 = br.ReadSingle();
            Unk78 = br.ReadUInt32();
            Unk79 = br.ReadUInt32();
            Unk80 = br.ReadUInt32();
            Unk81 = br.ReadUInt32();
            Unk82 = br.ReadUInt32();
            Unk83 = br.ReadUInt32();
            Unk84 = br.ReadUInt32();
            Unk85 = br.ReadInt32();
            Unk86 = br.ReadUInt32();
            Unk87 = br.ReadInt32();
            Unk88 = br.ReadUInt32();
            Unk89 = br.ReadInt32();

            if (Unk58 != 0)
            { }
            if (Unk61 != 0)
            { }
            if (Unk62 != 0)
            { }
            if (Unk66 != 0)
            { }
            if (Unk87 != 0)
            { }
            if (Unk89 != 0)
            { }
            if (Unk79 != NameHash)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk00);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
            bw.Write(Unk19);
            bw.Write(Unk20);
            bw.Write(Unk21);
            bw.Write(Unk22);
            bw.Write(Unk23);
            bw.Write(Unk24);
            bw.Write(Unk25);
            bw.Write(Unk26);
            bw.Write(Unk27);
            bw.Write(Unk28);
            bw.Write(Unk29);
            bw.Write(Unk30);
            bw.Write(Footsteps);
            bw.Write(Unk31);
            bw.Write(Unk32);
            bw.Write(AnimalFootsteps);
            bw.Write(AudioTrack2);
            bw.Write(Unk33);
            bw.Write(Unk34);
            bw.Write(Unk35);
            bw.Write(Unk36);
            bw.Write(Unk37);
            bw.Write(Unk38);
            bw.Write(Unk39);
            bw.Write(Unk40);
            bw.Write(Unk41);
            bw.Write(Unk42);
            bw.Write(Unk43);
            bw.Write(Unk44);
            bw.Write(Unk45);
            bw.Write(Unk46);
            bw.Write(Unk47);
            bw.Write(Unk48);
            bw.Write(Unk49);
            bw.Write(Unk50);
            bw.Write(Unk51);
            bw.Write(Unk52);
            bw.Write(Unk53);
            bw.Write(Unk54);
            bw.Write(Unk55);
            bw.Write(Unk56);
            bw.Write(Unk57);
            bw.Write(Unk58);
            bw.Write(Unk59);
            bw.Write(Unk60);
            bw.Write(Unk61);
            bw.Write(Unk62);
            bw.Write(Unk63);
            bw.Write(Unk64);
            bw.Write(Unk65);
            bw.Write(Unk66);
            bw.Write(Unk67);
            bw.Write(Unk68);
            bw.Write(Unk69);
            bw.Write(Unk70);
            bw.Write(Unk71);
            bw.Write(Unk72);
            bw.Write(Unk73);
            bw.Write(Unk74);
            bw.Write(Unk75);
            bw.Write(Unk76);
            bw.Write(Unk77);
            bw.Write(Unk78);
            bw.Write(Unk79);
            bw.Write(Unk80);
            bw.Write(Unk81);
            bw.Write(Unk82);
            bw.Write(Unk83);
            bw.Write(Unk84);
            bw.Write(Unk85);
            bw.Write(Unk86);
            bw.Write(Unk87);
            bw.Write(Unk88);
            bw.Write(Unk89);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk00", "0x" + Unk00.Hex);
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
            RelXml.StringTag(sb, indent, "Unk11", RelXml.HashString(Unk11));
            RelXml.StringTag(sb, indent, "Unk12", RelXml.HashString(Unk12));
            RelXml.StringTag(sb, indent, "Unk13", RelXml.HashString(Unk13));
            RelXml.StringTag(sb, indent, "Unk14", RelXml.HashString(Unk14));
            RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.ValueTag(sb, indent, "Unk17", Unk17.ToString());
            RelXml.ValueTag(sb, indent, "Unk18", Unk18.ToString());
            RelXml.ValueTag(sb, indent, "Unk19", FloatUtil.ToString(Unk19));
            RelXml.ValueTag(sb, indent, "Unk20", Unk20.ToString());
            RelXml.ValueTag(sb, indent, "Unk21", FloatUtil.ToString(Unk21));
            RelXml.ValueTag(sb, indent, "Unk22", FloatUtil.ToString(Unk22));
            RelXml.ValueTag(sb, indent, "Unk23", FloatUtil.ToString(Unk23));
            RelXml.ValueTag(sb, indent, "Unk24", FloatUtil.ToString(Unk24));
            RelXml.ValueTag(sb, indent, "Unk25", FloatUtil.ToString(Unk25));
            RelXml.ValueTag(sb, indent, "Unk26", FloatUtil.ToString(Unk26));
            RelXml.ValueTag(sb, indent, "Unk27", Unk27.ToString());
            RelXml.StringTag(sb, indent, "Unk28", RelXml.HashString(Unk28));
            RelXml.ValueTag(sb, indent, "Unk29", FloatUtil.ToString(Unk29));
            RelXml.ValueTag(sb, indent, "Unk30", FloatUtil.ToString(Unk30));
            RelXml.StringTag(sb, indent, "Footsteps", RelXml.HashString(Footsteps));
            RelXml.ValueTag(sb, indent, "Unk31", Unk31.ToString());
            RelXml.StringTag(sb, indent, "Unk32", RelXml.HashString(Unk32));
            RelXml.StringTag(sb, indent, "AnimalFootsteps", RelXml.HashString(AnimalFootsteps));
            RelXml.StringTag(sb, indent, "AudioTrack2", RelXml.HashString(AudioTrack2));
            RelXml.StringTag(sb, indent, "Unk33", RelXml.HashString(Unk33));
            RelXml.StringTag(sb, indent, "Unk34", RelXml.HashString(Unk34));
            RelXml.StringTag(sb, indent, "Unk35", RelXml.HashString(Unk35));
            RelXml.StringTag(sb, indent, "Unk36", RelXml.HashString(Unk36));
            RelXml.StringTag(sb, indent, "Unk37", RelXml.HashString(Unk37));
            RelXml.StringTag(sb, indent, "Unk38", RelXml.HashString(Unk38));
            RelXml.StringTag(sb, indent, "Unk39", RelXml.HashString(Unk39));
            RelXml.StringTag(sb, indent, "Unk40", RelXml.HashString(Unk40));
            RelXml.StringTag(sb, indent, "Unk41", RelXml.HashString(Unk41));
            RelXml.StringTag(sb, indent, "Unk42", RelXml.HashString(Unk42));
            RelXml.StringTag(sb, indent, "Unk43", RelXml.HashString(Unk43));
            RelXml.StringTag(sb, indent, "Unk44", RelXml.HashString(Unk44));
            RelXml.StringTag(sb, indent, "Unk45", RelXml.HashString(Unk45));
            RelXml.StringTag(sb, indent, "Unk46", RelXml.HashString(Unk46));
            RelXml.StringTag(sb, indent, "Unk47", RelXml.HashString(Unk47));
            RelXml.StringTag(sb, indent, "Unk48", RelXml.HashString(Unk48));
            RelXml.StringTag(sb, indent, "Unk49", RelXml.HashString(Unk49));
            RelXml.StringTag(sb, indent, "Unk50", RelXml.HashString(Unk50));
            RelXml.StringTag(sb, indent, "Unk51", RelXml.HashString(Unk51));
            RelXml.StringTag(sb, indent, "Unk52", RelXml.HashString(Unk52));
            RelXml.StringTag(sb, indent, "Unk53", RelXml.HashString(Unk53));
            RelXml.StringTag(sb, indent, "Unk54", RelXml.HashString(Unk54));
            RelXml.ValueTag(sb, indent, "Unk55", FloatUtil.ToString(Unk55));
            RelXml.StringTag(sb, indent, "Unk56", RelXml.HashString(Unk56));
            RelXml.StringTag(sb, indent, "Unk57", RelXml.HashString(Unk57));
            RelXml.ValueTag(sb, indent, "Unk58", Unk58.ToString());
            RelXml.ValueTag(sb, indent, "Unk59", Unk59.ToString());
            RelXml.ValueTag(sb, indent, "Unk60", FloatUtil.ToString(Unk60));
            RelXml.ValueTag(sb, indent, "Unk61", Unk61.ToString());
            RelXml.ValueTag(sb, indent, "Unk62", Unk62.ToString());
            RelXml.StringTag(sb, indent, "Unk63", RelXml.HashString(Unk63));
            RelXml.StringTag(sb, indent, "Unk64", RelXml.HashString(Unk64));
            RelXml.StringTag(sb, indent, "Unk65", RelXml.HashString(Unk65));
            RelXml.ValueTag(sb, indent, "Unk66", Unk66.ToString());
            RelXml.StringTag(sb, indent, "Unk67", RelXml.HashString(Unk67));
            RelXml.StringTag(sb, indent, "Unk68", RelXml.HashString(Unk68));
            RelXml.StringTag(sb, indent, "Unk69", RelXml.HashString(Unk69));
            RelXml.StringTag(sb, indent, "Unk70", RelXml.HashString(Unk70));
            RelXml.StringTag(sb, indent, "Unk71", RelXml.HashString(Unk71));
            RelXml.ValueTag(sb, indent, "Unk72", Unk72.ToString());
            RelXml.StringTag(sb, indent, "Unk73", RelXml.HashString(Unk73));
            RelXml.StringTag(sb, indent, "Unk74", RelXml.HashString(Unk74));
            RelXml.StringTag(sb, indent, "Unk75", RelXml.HashString(Unk75));
            RelXml.StringTag(sb, indent, "Unk76", RelXml.HashString(Unk76));
            RelXml.ValueTag(sb, indent, "Unk77", FloatUtil.ToString(Unk77));
            RelXml.StringTag(sb, indent, "Unk78", RelXml.HashString(Unk78));
            RelXml.StringTag(sb, indent, "Unk79", RelXml.HashString(Unk79));
            RelXml.StringTag(sb, indent, "Unk80", RelXml.HashString(Unk80));
            RelXml.StringTag(sb, indent, "Unk81", RelXml.HashString(Unk81));
            RelXml.StringTag(sb, indent, "Unk82", RelXml.HashString(Unk82));
            RelXml.StringTag(sb, indent, "Unk83", RelXml.HashString(Unk83));
            RelXml.StringTag(sb, indent, "Unk84", RelXml.HashString(Unk84));
            RelXml.ValueTag(sb, indent, "Unk85", Unk85.ToString());
            RelXml.StringTag(sb, indent, "Unk86", RelXml.HashString(Unk86));
            RelXml.ValueTag(sb, indent, "Unk87", Unk87.ToString());
            RelXml.StringTag(sb, indent, "Unk88", RelXml.HashString(Unk88));
            RelXml.ValueTag(sb, indent, "Unk89", Unk89.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk00 = Xml.GetChildUIntAttribute(node, "Unk00", "value");
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
            Unk11 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk11"));
            Unk12 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk12"));
            Unk13 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk13"));
            Unk14 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk14"));
            Unk15 = Xml.GetChildIntAttribute(node, "Unk15", "value");
            Unk16 = Xml.GetChildIntAttribute(node, "Unk16", "value");
            Unk17 = Xml.GetChildIntAttribute(node, "Unk17", "value");
            Unk18 = Xml.GetChildIntAttribute(node, "Unk18", "value");
            Unk19 = Xml.GetChildFloatAttribute(node, "Unk19", "value");
            Unk20 = Xml.GetChildIntAttribute(node, "Unk20", "value");
            Unk21 = Xml.GetChildFloatAttribute(node, "Unk21", "value");
            Unk22 = Xml.GetChildFloatAttribute(node, "Unk22", "value");
            Unk23 = Xml.GetChildFloatAttribute(node, "Unk23", "value");
            Unk24 = Xml.GetChildFloatAttribute(node, "Unk24", "value");
            Unk25 = Xml.GetChildFloatAttribute(node, "Unk25", "value");
            Unk26 = Xml.GetChildFloatAttribute(node, "Unk26", "value");
            Unk27 = Xml.GetChildIntAttribute(node, "Unk27", "value");
            Unk28 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk28"));
            Unk29 = Xml.GetChildFloatAttribute(node, "Unk29", "value");
            Unk30 = Xml.GetChildFloatAttribute(node, "Unk30", "value");
            Footsteps = XmlRel.GetHash(Xml.GetChildInnerText(node, "Footsteps"));
            Unk31 = Xml.GetChildIntAttribute(node, "Unk31", "value");
            Unk32 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk32"));
            AnimalFootsteps = XmlRel.GetHash(Xml.GetChildInnerText(node, "AnimalFootsteps"));
            AudioTrack2 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack2"));
            Unk33 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk33"));
            Unk34 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk34"));
            Unk35 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk35"));
            Unk36 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk36"));
            Unk37 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk37"));
            Unk38 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk38"));
            Unk39 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk39"));
            Unk40 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk40"));
            Unk41 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk41"));
            Unk42 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk42"));
            Unk43 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk43"));
            Unk44 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk44"));
            Unk45 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk45"));
            Unk46 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk46"));
            Unk47 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk47"));
            Unk48 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk48"));
            Unk49 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk49"));
            Unk50 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk50"));
            Unk51 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk51"));
            Unk52 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk52"));
            Unk53 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk53"));
            Unk54 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk54"));
            Unk55 = Xml.GetChildFloatAttribute(node, "Unk55", "value");
            Unk56 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk56"));
            Unk57 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk57"));
            Unk58 = Xml.GetChildIntAttribute(node, "Unk58", "value");
            Unk59 = Xml.GetChildIntAttribute(node, "Unk59", "value");
            Unk60 = Xml.GetChildFloatAttribute(node, "Unk60", "value");
            Unk61 = Xml.GetChildIntAttribute(node, "Unk61", "value");
            Unk62 = Xml.GetChildIntAttribute(node, "Unk62", "value");
            Unk63 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk63"));
            Unk64 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk64"));
            Unk65 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk65"));
            Unk66 = Xml.GetChildIntAttribute(node, "Unk66", "value");
            Unk67 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk67"));
            Unk68 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk68"));
            Unk69 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk69"));
            Unk70 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk70"));
            Unk71 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk71"));
            Unk72 = Xml.GetChildIntAttribute(node, "Unk72", "value");
            Unk73 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk73"));
            Unk74 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk74"));
            Unk75 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk75"));
            Unk76 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk76"));
            Unk77 = Xml.GetChildFloatAttribute(node, "Unk77", "value");
            Unk78 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk78"));
            Unk79 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk79"));
            Unk80 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk80"));
            Unk81 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk81"));
            Unk82 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk82"));
            Unk83 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk83"));
            Unk84 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk84"));
            Unk85 = Xml.GetChildIntAttribute(node, "Unk85", "value");
            Unk86 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk86"));
            Unk87 = Xml.GetChildIntAttribute(node, "Unk87", "value");
            Unk88 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk88"));
            Unk89 = Xml.GetChildIntAttribute(node, "Unk89", "value");

        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 124, 136, 140 };
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { Unk33, Unk34, Unk35, Unk36 };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk01, Unk02, Unk03, Unk04, Unk05, Unk06, Unk07, Unk08, Unk09, Unk10, Unk11, Unk12, Unk13, Unk14, Unk28, 
                Unk37, Unk38, Unk39, Unk40, Unk41, Unk42, Unk43, Unk44, Unk45, Unk46, Unk47, Unk48, Unk49, Unk50, Unk51, Unk52, Unk53,
                Unk56, Unk57, Unk63, Unk64, Unk65, Unk67, Unk68, Unk69, Unk70, Unk71, Unk73, Unk74, Unk75, Unk76,
                Unk80, Unk81, Unk82, Unk83, Unk84, Unk86, Unk88 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { Footsteps, Unk32, AnimalFootsteps, Unk54, Unk78, /*Unk79*/ };
        }
    }
    [TC(typeof(EXP))] public class Dat151Collision : Dat151RelData
    {
        public FlagsUint Unk00 { get; set; }
        public uint Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }
        public MetaHash Unk04 { get; set; }
        public MetaHash Unk05 { get; set; }
        public MetaHash Unk06 { get; set; }
        public MetaHash Unk07 { get; set; }
        public float Unk08 { get; set; }
        public MetaHash Unk09 { get; set; }
        public MetaHash Unk10 { get; set; }
        public MetaHash Unk11 { get; set; }
        public MetaHash Unk12 { get; set; }
        public MetaHash Unk13 { get; set; }
        public MetaHash Unk14 { get; set; }
        public MetaHash Unk15 { get; set; }
        public MetaHash Unk16 { get; set; }
        public MetaHash Unk17 { get; set; }
        public MetaHash Unk18 { get; set; }
        public MetaHash Unk19 { get; set; }
        public MetaHash Unk20 { get; set; }
        public float Unk21 { get; set; }
        public float Unk22 { get; set; }
        public float Unk23 { get; set; }
        public float Unk24 { get; set; }
        public float Unk25 { get; set; }
        public float Unk26 { get; set; }
        public MetaHash Unk27 { get; set; }
        public MetaHash Unk28 { get; set; }
        public MetaHash Unk29 { get; set; }//AudioMaterial
        public MetaHash Unk30 { get; set; }
        public MetaHash Unk31 { get; set; }
        public MetaHash Unk32 { get; set; }
        public MetaHash Unk33 { get; set; }
        public float Unk34 { get; set; }
        public float Unk35 { get; set; }
        public float Unk36 { get; set; }
        public float Unk37 { get; set; }
        public uint Unk38 { get; set; }
        public float Unk39 { get; set; }
        public float Unk40 { get; set; }
        public float Unk41 { get; set; }
        public float Unk42 { get; set; }
        public float Unk43 { get; set; }
        public float Unk44 { get; set; }
        public MetaHash Unk45 { get; set; }
        public MetaHash Unk46 { get; set; }
        public MetaHash Unk47 { get; set; }
        public MetaHash Unk48 { get; set; }//AudioMaterial
        public MetaHash Unk49 { get; set; }//AudioMaterial
        public uint HasAudioTracks { get; set; }
        public MetaHash AudioTrack0 { get; set; }//AudioMaterial
        public MetaHash AudioTrack1 { get; set; }//AudioMaterial

        public Dat151Collision(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Collision;
            TypeID = (byte)Type;
        }
        public Dat151Collision(RelData d, BinaryReader br) : base(d, br)
        {
            Unk00 = br.ReadUInt32();
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadUInt32();
            Unk03 = br.ReadUInt32();
            Unk04 = br.ReadUInt32();
            Unk05 = br.ReadUInt32();
            Unk06 = br.ReadUInt32();
            Unk07 = br.ReadUInt32();
            Unk08 = br.ReadSingle();
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadUInt32();
            Unk11 = br.ReadUInt32();
            Unk12 = br.ReadUInt32();
            Unk13 = br.ReadUInt32();
            Unk14 = br.ReadUInt32();
            Unk15 = br.ReadUInt32();
            Unk16 = br.ReadUInt32();
            Unk17 = br.ReadUInt32();
            Unk18 = br.ReadUInt32();
            Unk19 = br.ReadUInt32();
            Unk20 = br.ReadUInt32();
            Unk21 = br.ReadSingle();
            Unk22 = br.ReadSingle();
            Unk23 = br.ReadSingle();
            Unk24 = br.ReadSingle();
            Unk25 = br.ReadSingle();
            Unk26 = br.ReadSingle();
            Unk27 = br.ReadUInt32();
            Unk28 = br.ReadUInt32();
            Unk29 = br.ReadUInt32();
            Unk30 = br.ReadUInt32();
            Unk31 = br.ReadUInt32();
            Unk32 = br.ReadUInt32();
            Unk33 = br.ReadUInt32();
            Unk34 = br.ReadSingle();
            Unk35 = br.ReadSingle();
            Unk36 = br.ReadSingle();
            Unk37 = br.ReadSingle();
            Unk38 = br.ReadUInt32();
            Unk39 = br.ReadSingle();
            Unk40 = br.ReadSingle();
            Unk41 = br.ReadSingle();
            Unk42 = br.ReadSingle();
            Unk43 = br.ReadSingle();
            Unk44 = br.ReadSingle();
            Unk45 = br.ReadUInt32();
            Unk46 = br.ReadUInt32();
            Unk47 = br.ReadUInt32();
            Unk48 = br.ReadUInt32();
            Unk49 = br.ReadUInt32();
            HasAudioTracks = br.ReadUInt32();
            if (HasAudioTracks > 0)
            {
                AudioTrack0 = br.ReadUInt32();
                AudioTrack1 = br.ReadUInt32();
            }
            switch (HasAudioTracks)
            {
                case 0:
                case 1:
                    break;
                default:
                    break;
            }

            if (Unk00 != 0)
            { }
            if (Unk01 != 0)
            { }
            if (Unk38 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk00);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
            bw.Write(Unk19);
            bw.Write(Unk20);
            bw.Write(Unk21);
            bw.Write(Unk22);
            bw.Write(Unk23);
            bw.Write(Unk24);
            bw.Write(Unk25);
            bw.Write(Unk26);
            bw.Write(Unk27);
            bw.Write(Unk28);
            bw.Write(Unk29);
            bw.Write(Unk30);
            bw.Write(Unk31);
            bw.Write(Unk32);
            bw.Write(Unk33);
            bw.Write(Unk34);
            bw.Write(Unk35);
            bw.Write(Unk36);
            bw.Write(Unk37);
            bw.Write(Unk38);
            bw.Write(Unk39);
            bw.Write(Unk40);
            bw.Write(Unk41);
            bw.Write(Unk42);
            bw.Write(Unk43);
            bw.Write(Unk44);
            bw.Write(Unk45);
            bw.Write(Unk46);
            bw.Write(Unk47);
            bw.Write(Unk48);
            bw.Write(Unk49);
            bw.Write(HasAudioTracks);
            if (HasAudioTracks > 0)
            {
                bw.Write(AudioTrack0);
                bw.Write(AudioTrack1);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk00", "0x" + Unk00.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.ValueTag(sb, indent, "Unk08", FloatUtil.ToString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
            RelXml.StringTag(sb, indent, "Unk11", RelXml.HashString(Unk11));
            RelXml.StringTag(sb, indent, "Unk12", RelXml.HashString(Unk12));
            RelXml.StringTag(sb, indent, "Unk13", RelXml.HashString(Unk13));
            RelXml.StringTag(sb, indent, "Unk14", RelXml.HashString(Unk14));
            RelXml.StringTag(sb, indent, "Unk15", RelXml.HashString(Unk15));
            RelXml.StringTag(sb, indent, "Unk16", RelXml.HashString(Unk16));
            RelXml.StringTag(sb, indent, "Unk17", RelXml.HashString(Unk17));
            RelXml.StringTag(sb, indent, "Unk18", RelXml.HashString(Unk18));
            RelXml.StringTag(sb, indent, "Unk19", RelXml.HashString(Unk19));
            RelXml.StringTag(sb, indent, "Unk20", RelXml.HashString(Unk20));
            RelXml.ValueTag(sb, indent, "Unk21", FloatUtil.ToString(Unk21));
            RelXml.ValueTag(sb, indent, "Unk22", FloatUtil.ToString(Unk22));
            RelXml.ValueTag(sb, indent, "Unk23", FloatUtil.ToString(Unk23));
            RelXml.ValueTag(sb, indent, "Unk24", FloatUtil.ToString(Unk24));
            RelXml.ValueTag(sb, indent, "Unk25", FloatUtil.ToString(Unk25));
            RelXml.ValueTag(sb, indent, "Unk26", FloatUtil.ToString(Unk26));
            RelXml.StringTag(sb, indent, "Unk27", RelXml.HashString(Unk27));
            RelXml.StringTag(sb, indent, "Unk28", RelXml.HashString(Unk28));
            RelXml.StringTag(sb, indent, "Unk29", RelXml.HashString(Unk29));
            RelXml.StringTag(sb, indent, "Unk30", RelXml.HashString(Unk30));
            RelXml.StringTag(sb, indent, "Unk31", RelXml.HashString(Unk31));
            RelXml.StringTag(sb, indent, "Unk32", RelXml.HashString(Unk32));
            RelXml.StringTag(sb, indent, "Unk33", RelXml.HashString(Unk33));
            RelXml.ValueTag(sb, indent, "Unk34", FloatUtil.ToString(Unk34));
            RelXml.ValueTag(sb, indent, "Unk35", FloatUtil.ToString(Unk35));
            RelXml.ValueTag(sb, indent, "Unk36", FloatUtil.ToString(Unk36));
            RelXml.ValueTag(sb, indent, "Unk37", FloatUtil.ToString(Unk37));
            RelXml.ValueTag(sb, indent, "Unk38", Unk38.ToString());
            RelXml.ValueTag(sb, indent, "Unk39", FloatUtil.ToString(Unk39));
            RelXml.ValueTag(sb, indent, "Unk40", FloatUtil.ToString(Unk40));
            RelXml.ValueTag(sb, indent, "Unk41", FloatUtil.ToString(Unk41));
            RelXml.ValueTag(sb, indent, "Unk42", FloatUtil.ToString(Unk42));
            RelXml.ValueTag(sb, indent, "Unk43", FloatUtil.ToString(Unk43));
            RelXml.ValueTag(sb, indent, "Unk44", FloatUtil.ToString(Unk44));
            RelXml.StringTag(sb, indent, "Unk45", RelXml.HashString(Unk45));
            RelXml.StringTag(sb, indent, "Unk46", RelXml.HashString(Unk46));
            RelXml.StringTag(sb, indent, "Unk47", RelXml.HashString(Unk47));
            RelXml.StringTag(sb, indent, "Unk48", RelXml.HashString(Unk48));
            RelXml.StringTag(sb, indent, "Unk49", RelXml.HashString(Unk49));
            //RelXml.ValueTag(sb, indent, "HasAudioTracks", HasAudioTracks.ToString());
            if (HasAudioTracks > 0)
            {
                RelXml.StringTag(sb, indent, "AudioTrack0", RelXml.HashString(AudioTrack0));
                RelXml.StringTag(sb, indent, "AudioTrack1", RelXml.HashString(AudioTrack1));
            }
        }
        public override void ReadXml(XmlNode node)
        {
            Unk00 = Xml.GetChildUIntAttribute(node, "Unk00", "value");
            Unk01 = Xml.GetChildUIntAttribute(node, "Unk01", "value");
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Unk08 = Xml.GetChildFloatAttribute(node, "Unk08", "value");
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
            Unk11 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk11"));
            Unk12 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk12"));
            Unk13 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk13"));
            Unk14 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk14"));
            Unk15 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk15"));
            Unk16 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk16"));
            Unk17 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk17"));
            Unk18 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk18"));
            Unk19 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk19"));
            Unk20 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk20"));
            Unk21 = Xml.GetChildFloatAttribute(node, "Unk21", "value");
            Unk22 = Xml.GetChildFloatAttribute(node, "Unk22", "value");
            Unk23 = Xml.GetChildFloatAttribute(node, "Unk23", "value");
            Unk24 = Xml.GetChildFloatAttribute(node, "Unk24", "value");
            Unk25 = Xml.GetChildFloatAttribute(node, "Unk25", "value");
            Unk26 = Xml.GetChildFloatAttribute(node, "Unk26", "value");
            Unk27 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk27"));
            Unk28 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk28"));
            Unk29 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk29"));
            Unk30 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk30"));
            Unk31 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk31"));
            Unk32 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk32"));
            Unk33 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk33"));
            Unk34 = Xml.GetChildFloatAttribute(node, "Unk34", "value");
            Unk35 = Xml.GetChildFloatAttribute(node, "Unk35", "value");
            Unk36 = Xml.GetChildFloatAttribute(node, "Unk36", "value");
            Unk37 = Xml.GetChildFloatAttribute(node, "Unk37", "value");
            Unk38 = Xml.GetChildUIntAttribute(node, "Unk38", "value");
            Unk39 = Xml.GetChildFloatAttribute(node, "Unk39", "value");
            Unk40 = Xml.GetChildFloatAttribute(node, "Unk40", "value");
            Unk41 = Xml.GetChildFloatAttribute(node, "Unk41", "value");
            Unk42 = Xml.GetChildFloatAttribute(node, "Unk42", "value");
            Unk43 = Xml.GetChildFloatAttribute(node, "Unk43", "value");
            Unk44 = Xml.GetChildFloatAttribute(node, "Unk44", "value");
            Unk45 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk45"));
            Unk46 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk46"));
            Unk47 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk47"));
            Unk48 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk48"));
            Unk49 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk49"));
            if (node.SelectSingleNode("AudioTrack0") != null)
            {
                HasAudioTracks = 1;
                AudioTrack0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack0"));
                AudioTrack1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack1"));
            }
        }
        public override uint[] GetHashTableOffsets()
        {
            if (HasAudioTracks > 0) return new uint[] { 204, 208 };
            else return null;
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { Unk09, Unk10, Unk11, Unk12, Unk13, Unk14, Unk15, Unk16, Unk17, Unk18, Unk19, Unk20, Unk27, Unk28 };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk02, Unk03, Unk04, Unk05, Unk06, Unk07, Unk30, Unk31, Unk32, Unk33, Unk45, Unk46, Unk47 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { Unk29, Unk48, Unk49, AudioTrack0, AudioTrack1 };
        }
    }
    [TC(typeof(EXP))] public class Dat151Door : Dat151RelData
    {
        public MetaHash SoundSet { get; set; }
        public MetaHash Params { get; set; }//type Dat151DoorParams
        public float Unk1 { get; set; }

        public Dat151Door(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Door;
            TypeID = (byte)Type;
        }
        public Dat151Door(RelData d, BinaryReader br) : base(d, br)
        {
            SoundSet = br.ReadUInt32();
            Params = br.ReadUInt32();
            Unk1 = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(SoundSet);
            bw.Write(Params);
            bw.Write(Unk1);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "SoundSet", RelXml.HashString(SoundSet));
            RelXml.StringTag(sb, indent, "Params", RelXml.HashString(Params));
            RelXml.ValueTag(sb, indent, "Unk1", FloatUtil.ToString(Unk1));
        }
        public override void ReadXml(XmlNode node)
        {
            SoundSet = XmlRel.GetHash(Xml.GetChildInnerText(node, "SoundSet"));
            Params = XmlRel.GetHash(Xml.GetChildInnerText(node, "Params"));
            Unk1 = Xml.GetChildFloatAttribute(node, "Unk1", "value");
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 4 };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { SoundSet };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { Params };
        }
    }
    [TC(typeof(EXP))] public class Dat151AnimalFootsteps : Dat151RelData
    {
        public uint AudioItemCount { get; set; }
        public Dat151HashPair[] AudioItems { get; set; }

        public Dat151AnimalFootsteps(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.AnimalFootsteps;
            TypeID = (byte)Type;
        }
        public Dat151AnimalFootsteps(RelData d, BinaryReader br) : base(d, br)
        {
            AudioItemCount = br.ReadUInt32();
            var items = new Dat151HashPair[AudioItemCount];
            for (uint i = 0; i < AudioItemCount; i++)
            {
                items[i] = new Dat151HashPair(br);
            }
            AudioItems = items;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(AudioItemCount);
            for (uint i = 0; i < AudioItemCount; i++)
            {
                AudioItems[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, AudioItems, indent, "AudioItems");
        }
        public override void ReadXml(XmlNode node)
        {
            AudioItems = XmlRel.ReadItemArray<Dat151HashPair>(node, "AudioItems");
            AudioItemCount = (uint)(AudioItems?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < AudioItemCount; i++)
            {
                offsets.Add(8 + i * 8);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            foreach (var item in AudioItems)
            {
                list.Add(item.Hash1);
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151ForceRadioTrackAction : Dat151RelData
    {
        public FlagsUint Unk0 { get; set; }
        public int Unk1 { get; set; }
        public int Unk2 { get; set; }
        public MetaHash AudioTrack0 { get; set; }//unused
        public MetaHash AudioTrack1 { get; set; }//unused
        public float Unk3 { get; set; }
        public MetaHash RadioStation { get; set; }
        public int Unk5 { get; set; }
        public uint AudioTracksCount { get; set; }
        public MetaHash[] AudioTracks { get; set; }

        public Dat151ForceRadioTrackAction(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.ForceRadioTrackAction;
            TypeID = (byte)Type;
        }
        public Dat151ForceRadioTrackAction(RelData d, BinaryReader br) : base(d, br)
        {
            Unk0 = br.ReadUInt32();
            Unk1 = br.ReadInt32();
            Unk2 = br.ReadInt32();
            AudioTrack0 = br.ReadUInt32();
            AudioTrack1 = br.ReadUInt32();
            Unk3 = br.ReadSingle();
            RadioStation = br.ReadUInt32();
            Unk5 = br.ReadInt32();
            AudioTracksCount = br.ReadUInt32();
            var tracks = new MetaHash[AudioTracksCount];
            for (var i = 0; i < AudioTracksCount; i++)
            {
                tracks[i] = br.ReadUInt32();
            }
            AudioTracks = tracks;

            if (Unk1 != 0)
            { }
            if (Unk2 != 0)
            { }
            if (Unk5 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk0);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(AudioTrack0);
            bw.Write(AudioTrack1);
            bw.Write(Unk3);
            bw.Write(RadioStation);
            bw.Write(Unk5);
            bw.Write(AudioTracksCount);
            for (var i = 0; i < AudioTracksCount; i++)
            {
                bw.Write(AudioTracks[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk0", "0x" + Unk0.Hex);
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
            RelXml.ValueTag(sb, indent, "Unk2", Unk2.ToString());
            RelXml.StringTag(sb, indent, "AudioTrack0", RelXml.HashString(AudioTrack0));
            RelXml.StringTag(sb, indent, "AudioTrack1", RelXml.HashString(AudioTrack1));
            RelXml.ValueTag(sb, indent, "Unk3", FloatUtil.ToString(Unk3));
            RelXml.StringTag(sb, indent, "RadioStation", RelXml.HashString(RadioStation));
            RelXml.ValueTag(sb, indent, "Unk5", Unk5.ToString());
            RelXml.WriteHashItemArray(sb, AudioTracks, indent, "ChildSounds");
        }
        public override void ReadXml(XmlNode node)
        {
            Unk0 = Xml.GetChildUIntAttribute(node, "Unk0", "value");
            Unk1 = Xml.GetChildIntAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildIntAttribute(node, "Unk2", "value");
            AudioTrack0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack0"));
            AudioTrack1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack1"));
            Unk3 = Xml.GetChildFloatAttribute(node, "Unk3", "value");
            RadioStation = XmlRel.GetHash(Xml.GetChildInnerText(node, "RadioStation"));
            Unk5 = Xml.GetChildIntAttribute(node, "Unk5", "value");
            AudioTracks = XmlRel.ReadHashItemArray(node, "ChildSounds");
            AudioTracksCount = (uint)(AudioTracks?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            offsets.Add(12);
            offsets.Add(16);
            for (uint i = 0; i < AudioTracksCount; i++)
            {
                offsets.Add(36 + i * 4);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            list.Add(AudioTrack0);
            list.Add(AudioTrack1);
            list.Add(RadioStation);
            if (AudioTracks != null)
            {
                list.AddRange(AudioTracks);
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151RadioDjSpeechAction : Dat151RelData
    {
        public FlagsUint Unk0 { get; set; }
        public int Unk1 { get; set; }
        public int Unk2 { get; set; }
        public MetaHash AudioTrack0 { get; set; }//unused
        public MetaHash AudioTrack1 { get; set; }//unused
        public float Unk3 { get; set; }
        public MetaHash RadioStation { get; set; }
        public int Unk5 { get; set; }

        public Dat151RadioDjSpeechAction(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.RadioDJSpeechAction;
            TypeID = (byte)Type;
        }
        public Dat151RadioDjSpeechAction(RelData d, BinaryReader br) : base(d, br)
        {
            Unk0 = br.ReadUInt32();
            Unk1 = br.ReadInt32();
            Unk2 = br.ReadInt32();
            AudioTrack0 = br.ReadUInt32();
            AudioTrack1 = br.ReadUInt32();
            Unk3 = br.ReadSingle();
            RadioStation = br.ReadUInt32();
            Unk5 = br.ReadInt32();

            if (Unk1 != 0)
            { }
            if (Unk2 != 0)
            { }
            if (Unk3 != 0)
            { }
            if (RadioStation != 0)
            { }
            if (Unk5 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk0);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(AudioTrack0);
            bw.Write(AudioTrack1);
            bw.Write(Unk3);
            bw.Write(RadioStation);
            bw.Write(Unk5);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk0", "0x" + Unk0.Hex);
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
            RelXml.ValueTag(sb, indent, "Unk2", Unk2.ToString());
            RelXml.StringTag(sb, indent, "AudioTrack0", RelXml.HashString(AudioTrack0));
            RelXml.StringTag(sb, indent, "AudioTrack1", RelXml.HashString(AudioTrack1));
            RelXml.ValueTag(sb, indent, "Unk3", FloatUtil.ToString(Unk3));
            RelXml.StringTag(sb, indent, "RadioStation", RelXml.HashString(RadioStation));
            RelXml.ValueTag(sb, indent, "Unk5", Unk5.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk0 = Xml.GetChildUIntAttribute(node, "Unk0", "value");
            Unk1 = Xml.GetChildIntAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildIntAttribute(node, "Unk2", "value");
            AudioTrack0 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack0"));
            AudioTrack1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "AudioTrack1"));
            Unk3 = Xml.GetChildFloatAttribute(node, "Unk3", "value");
            RadioStation = XmlRel.GetHash(Xml.GetChildInnerText(node, "RadioStation"));
            Unk5 = Xml.GetChildIntAttribute(node, "Unk5", "value");
        }
        public override uint[] GetHashTableOffsets()
        {
            return new uint[] { 12, 16 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { AudioTrack0, AudioTrack1, RadioStation };
        }
    }
    [TC(typeof(EXP))] public class Dat151MicrophoneList : Dat151RelData
    {
        public uint AudioItemCount { get; set; }
        public Dat151HashPair[] AudioItems { get; set; }//types: name?, Microphone

        public Dat151MicrophoneList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.MicrophoneList;
            TypeID = (byte)Type;
        }
        public Dat151MicrophoneList(RelData d, BinaryReader br) : base(d, br)
        {
            AudioItemCount = br.ReadUInt32();
            var items = new Dat151HashPair[AudioItemCount];
            for (var i = 0; i < AudioItemCount; i++)
            {
                items[i] = new Dat151HashPair(br);
            }
            AudioItems = items;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(AudioItemCount);
            for (var i = 0; i < AudioItemCount; i++)
            {
                AudioItems[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, AudioItems, indent, "AudioItems");
        }
        public override void ReadXml(XmlNode node)
        {
            AudioItems = XmlRel.ReadItemArray<Dat151HashPair>(node, "AudioItems");
            AudioItemCount = (uint)(AudioItems?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < AudioItemCount; i++)
            {
                offsets.Add(8 + i * 8);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            if (AudioItems != null)
            {
                foreach (var item in AudioItems)
                {
                    list.Add(item.Hash1);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151DoorList : Dat151RelData //doors/gates
    {
        public uint AudioItemCount { get; set; }
        public Dat151HashPair[] AudioItems { get; set; }// prop name, Door

        public Dat151DoorList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.DoorList;
            TypeID = (byte)Type;
        }
        public Dat151DoorList(RelData d, BinaryReader br) : base(d, br)
        {
            AudioItemCount = br.ReadUInt32();
            var items = new Dat151HashPair[AudioItemCount];
            for (var i = 0; i < AudioItemCount; i++)
            {
                items[i] = new Dat151HashPair(br);
            }
            AudioItems = items;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(AudioItemCount);
            for (var i = 0; i < AudioItemCount; i++)
            {
                AudioItems[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, AudioItems, indent, "AudioItems");
        }
        public override void ReadXml(XmlNode node)
        {
            AudioItems = XmlRel.ReadItemArray<Dat151HashPair>(node, "AudioItems");
            AudioItemCount = (uint)(AudioItems?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < AudioItemCount; i++)
            {
                offsets.Add(8 + i * 8);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            if (AudioItems != null)
            {
                foreach (var item in AudioItems)
                {
                    list.Add(item.Hash1);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151ShoeList : Dat151RelData
    {
        public uint AudioItemCount { get; set; }
        public Dat151HashPair[] AudioItems { get; set; }//types: name?, Shoe

        public Dat151ShoeList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.ShoeList;
            TypeID = (byte)Type;
        }
        public Dat151ShoeList(RelData d, BinaryReader br) : base(d, br)
        {
            AudioItemCount = br.ReadUInt32();
            var items = new Dat151HashPair[AudioItemCount];
            for (var i = 0; i < AudioItemCount; i++)
            {
                items[i] = new Dat151HashPair(br);
            }
            AudioItems = items;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(AudioItemCount);
            for (var i = 0; i < AudioItemCount; i++)
            {
                AudioItems[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, AudioItems, indent, "AudioItems");
        }
        public override void ReadXml(XmlNode node)
        {
            AudioItems = XmlRel.ReadItemArray<Dat151HashPair>(node, "AudioItems");
            AudioItemCount = (uint)(AudioItems?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < AudioItemCount; i++)
            {
                offsets.Add(8 + i * 8);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            if (AudioItems != null)
            {
                foreach (var item in AudioItems)
                {
                    list.Add(item.Hash1);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151ClothList : Dat151RelData
    {
        public uint AudioItemCount { get; set; }
        public Dat151HashPair[] AudioItems { get; set; }//types: name?, ClothType

        public Dat151ClothList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.ClothList;
            TypeID = (byte)Type;
        }
        public Dat151ClothList(RelData d, BinaryReader br) : base(d, br)
        {
            AudioItemCount = br.ReadUInt32();
            var items = new Dat151HashPair[AudioItemCount];
            for (var i = 0; i < AudioItemCount; i++)
            {
                items[i] = new Dat151HashPair(br);
            }
            AudioItems = items;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(AudioItemCount);
            for (var i = 0; i < AudioItemCount; i++)
            {
                AudioItems[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, AudioItems, indent, "AudioItems");
        }
        public override void ReadXml(XmlNode node)
        {
            AudioItems = XmlRel.ReadItemArray<Dat151HashPair>(node, "AudioItems");
            AudioItemCount = (uint)(AudioItems?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < AudioItemCount; i++)
            {
                offsets.Add(8 + i * 8);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            if (AudioItems != null)
            {
                foreach (var item in AudioItems)
                {
                    list.Add(item.Hash1);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151VehicleRecordList : Dat151RelData
    {
        public uint AudioItemCount { get; set; }
        public Dat151HashPair[] AudioItems { get; set; }//types: ???, VehicleRecord

        public Dat151VehicleRecordList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.VehicleRecordList;
            TypeID = (byte)Type;
        }
        public Dat151VehicleRecordList(RelData d, BinaryReader br) : base(d, br)
        {
            AudioItemCount = br.ReadUInt32();
            var items = new Dat151HashPair[AudioItemCount];
            for (var i = 0; i < AudioItemCount; i++)
            {
                items[i] = new Dat151HashPair(br);
            }
            AudioItems = items;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(AudioItemCount);
            for (var i = 0; i < AudioItemCount; i++)
            {
                AudioItems[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, AudioItems, indent, "AudioItems");
        }
        public override void ReadXml(XmlNode node)
        {
            AudioItems = XmlRel.ReadItemArray<Dat151HashPair>(node, "AudioItems");
            AudioItemCount = (uint)(AudioItems?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < AudioItemCount; i++)
            {
                offsets.Add(8 + i * 8);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            if (AudioItems != null)
            {
                foreach (var item in AudioItems)
                {
                    list.Add(item.Hash1);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151WeatherTypeList : Dat151RelData
    {
        public uint AudioItemCount { get; set; }
        public Dat151HashPair[] AudioItems { get; set; }//types: name, WeatherType

        public Dat151WeatherTypeList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.WeatherTypeList;
            TypeID = (byte)Type;
        }
        public Dat151WeatherTypeList(RelData d, BinaryReader br) : base(d, br)
        {
            AudioItemCount = br.ReadUInt32();
            var items = new Dat151HashPair[AudioItemCount];
            for (var i = 0; i < AudioItemCount; i++)
            {
                items[i] = new Dat151HashPair(br);
            }
            AudioItems = items;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(AudioItemCount);
            for (var i = 0; i < AudioItemCount; i++)
            {
                AudioItems[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, AudioItems, indent, "AudioItems");
        }
        public override void ReadXml(XmlNode node)
        {
            AudioItems = XmlRel.ReadItemArray<Dat151HashPair>(node, "AudioItems");
            AudioItemCount = (uint)(AudioItems?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < AudioItemCount; i++)
            {
                offsets.Add(8 + i * 8);
            }
            return offsets.ToArray();
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            if (AudioItems != null)
            {
                foreach (var item in AudioItems)
                {
                    list.Add(item.Hash1);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151ShoreLinePool : Dat151RelData
    {
        public FlagsUint Unk01 { get; set; }
        public Vector4 Unk02 { get; set; }
        public int Unk03 { get; set; }
        public int Unk04 { get; set; }
        public int Unk05 { get; set; }
        public int Unk06 { get; set; }
        public int Unk07 { get; set; }
        public int Unk08 { get; set; }
        public int Unk09 { get; set; }
        public int Unk10 { get; set; }
        public int Unk11 { get; set; }
        public float Unk12 { get; set; }//really float? or hash?
        public int PointsCount { get; set; }
        public Vector2[] Points { get; set; }


        public Dat151ShoreLinePool(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.ShoreLinePool;
            TypeID = (byte)Type;
        }
        public Dat151ShoreLinePool(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            Unk03 = br.ReadInt32();
            Unk04 = br.ReadInt32();
            Unk05 = br.ReadInt32();
            Unk06 = br.ReadInt32();
            Unk07 = br.ReadInt32();
            Unk08 = br.ReadInt32();
            Unk09 = br.ReadInt32();
            Unk10 = br.ReadInt32();
            Unk11 = br.ReadInt32();
            Unk12 = br.ReadSingle();

            PointsCount = br.ReadInt32();
            var points = new Vector2[PointsCount];
            for (int i = 0; i < PointsCount; i++)
            {
                points[i] = new Vector2(br.ReadSingle(), br.ReadSingle());
            }
            Points = points;

            //switch (Unk12)
            //{
            //    case 4.267251f:
            //    case 2.055879f:
            //        break;
            //    default:
            //        break;
            //}

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02.X);
            bw.Write(Unk02.Y);
            bw.Write(Unk02.Z);
            bw.Write(Unk02.W);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);

            bw.Write(PointsCount);
            for (int i = 0; i < PointsCount; i++)
            {
                bw.Write(Points[i].X);
                bw.Write(Points[i].Y);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", "0x" + Unk01.Hex);
            RelXml.SelfClosingTag(sb, indent, "Unk02 " + FloatUtil.GetVector4XmlString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.ValueTag(sb, indent, "Unk06", Unk06.ToString());
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.ValueTag(sb, indent, "Unk11", Unk11.ToString());
            RelXml.ValueTag(sb, indent, "Unk12", FloatUtil.ToString(Unk12));
            //RelXml.StringTag(sb, indent, "Unk12", RelXml.HashString(Unk12));
            RelXml.WriteRawArray(sb, Points, indent, "Points", "", RelXml.FormatVector2, 1);
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildUIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildVector4Attributes(node, "Unk02");
            Unk03 = Xml.GetChildIntAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildIntAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildIntAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildIntAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildIntAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildIntAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildIntAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildIntAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildIntAttribute(node, "Unk11", "value");
            Unk12 = Xml.GetChildFloatAttribute(node, "Unk12", "value");
            //Unk12 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk12"));
            Points = Xml.GetChildRawVector2Array(node, "Points");
            PointsCount = Points?.Length ?? 0;
        }
    }
    [TC(typeof(EXP))] public class Dat151ShoreLineLake : Dat151RelData
    {
        public FlagsUint Unk01 { get; set; }
        public Vector4 Unk02 { get; set; }
        public int Unk03 { get; set; }
        public int Unk04 { get; set; }
        public uint Unk05 { get; set; }
        public int PointsCount { get; set; }
        public Vector2[] Points { get; set; }

        public Dat151ShoreLineLake(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.ShoreLineLake;
            TypeID = (byte)Type;
        }
        public Dat151ShoreLineLake(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            Unk03 = br.ReadInt32();
            Unk04 = br.ReadInt32();
            Unk05 = br.ReadUInt32();

            byte b1 = (byte)((Unk05) & 0xFF);
            byte b2 = (byte)((Unk05>>8) & 0xFF);
            PointsCount = b2;

            var points = new Vector2[PointsCount];
            for (int i = 0; i < PointsCount; i++)
            {
                points[i] = new Vector2(br.ReadSingle(), br.ReadSingle());
            }
            Points = points;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02.X);
            bw.Write(Unk02.Y);
            bw.Write(Unk02.Z);
            bw.Write(Unk02.W);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);

            //byte b1 = (byte)((Unk05) & 0xFF);
            //byte b2 = (byte)((Unk05 >> 8) & 0xFF);
            //PointsCount = b2;

            for (int i = 0; i < PointsCount; i++)
            {
                bw.Write(Points[i].X);
                bw.Write(Points[i].Y);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", "0x" + Unk01.Hex);
            RelXml.SelfClosingTag(sb, indent, "Unk02 " + FloatUtil.GetVector4XmlString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.WriteRawArray(sb, Points, indent, "Points", "", RelXml.FormatVector2, 1);
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildUIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildVector4Attributes(node, "Unk02");
            Unk03 = Xml.GetChildIntAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildIntAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildUIntAttribute(node, "Unk05", "value");
            Points = Xml.GetChildRawVector2Array(node, "Points");
            PointsCount = Points?.Length ?? 0;
        }
    }
    [TC(typeof(EXP))] public class Dat151ShoreLineRiver : Dat151RelData
    {
        public FlagsUint Unk01 { get; set; }
        public Vector4 Unk02 { get; set; }
        public float Unk03 { get; set; }
        public uint Unk04 { get; set; }
        public uint Unk05 { get; set; }
        public uint Unk06 { get; set; }
        public uint PointsCount { get; set; }
        public Vector3[] Points { get; set; }

        public Dat151ShoreLineRiver(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.ShoreLineRiver;
            TypeID = (byte)Type;
        }
        public Dat151ShoreLineRiver(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadUInt32();
            Unk05 = br.ReadUInt32();
            Unk06 = br.ReadUInt32();
            PointsCount = br.ReadUInt32();

            var points = new Vector3[PointsCount];
            for (int i = 0; i < PointsCount; i++)
            {
                points[i] = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            }
            Points = points;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02.X);
            bw.Write(Unk02.Y);
            bw.Write(Unk02.Z);
            bw.Write(Unk02.W);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(PointsCount);

            for (int i = 0; i < PointsCount; i++)
            {
                bw.Write(Points[i].X);
                bw.Write(Points[i].Y);
                bw.Write(Points[i].Z);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", "0x" + Unk01.Hex);
            RelXml.SelfClosingTag(sb, indent, "Unk02 " + FloatUtil.GetVector4XmlString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.ValueTag(sb, indent, "Unk06", Unk06.ToString());
            RelXml.WriteRawArray(sb, Points, indent, "Points", "", RelXml.FormatVector3, 1);
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildUIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildVector4Attributes(node, "Unk02");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildUIntAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildUIntAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildUIntAttribute(node, "Unk06", "value");
            Points = Xml.GetChildRawVector3Array(node, "Points");
            PointsCount = (uint)(Points?.Length ?? 0);
        }
    }
    [TC(typeof(EXP))] public class Dat151ShoreLineOcean : Dat151RelData
    {
        public FlagsUint Unk01 { get; set; }
        public Vector4 Unk02 { get; set; }
        public float Unk03 { get; set; }
        public uint Unk04 { get; set; }
        public MetaHash Unk05 { get; set; }//adjacent shoreline? links to same type, not included in children list due to large chain!
        public float Unk06 { get; set; }
        public float Unk07 { get; set; }
        public float Unk08 { get; set; }
        public float Unk09 { get; set; }
        public float Unk10 { get; set; }
        public float Unk11 { get; set; }
        public float Unk12 { get; set; }
        public uint PointsCount { get; set; }
        public Vector2[] Points { get; set; }

        public Dat151ShoreLineOcean(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.ShoreLineOcean;
            TypeID = (byte)Type;
        }
        public Dat151ShoreLineOcean(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadUInt32();
            Unk05 = br.ReadUInt32();
            Unk06 = br.ReadSingle();
            Unk07 = br.ReadSingle();
            Unk08 = br.ReadSingle();
            Unk09 = br.ReadSingle();
            Unk10 = br.ReadSingle();
            Unk11 = br.ReadSingle();
            Unk12 = br.ReadSingle();

            PointsCount = br.ReadUInt32();

            var points = new Vector2[PointsCount];
            for (int i = 0; i < PointsCount; i++)
            {
                points[i] = new Vector2(br.ReadSingle(), br.ReadSingle());
            }
            Points = points;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02.X);
            bw.Write(Unk02.Y);
            bw.Write(Unk02.Z);
            bw.Write(Unk02.W);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);

            bw.Write(PointsCount);

            for (int i = 0; i < PointsCount; i++)
            {
                bw.Write(Points[i].X);
                bw.Write(Points[i].Y);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", "0x" + Unk01.Hex);
            RelXml.SelfClosingTag(sb, indent, "Unk02 " + FloatUtil.GetVector4XmlString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", FloatUtil.ToString(Unk07));
            RelXml.ValueTag(sb, indent, "Unk08", FloatUtil.ToString(Unk08));
            RelXml.ValueTag(sb, indent, "Unk09", FloatUtil.ToString(Unk09));
            RelXml.ValueTag(sb, indent, "Unk10", FloatUtil.ToString(Unk10));
            RelXml.ValueTag(sb, indent, "Unk11", FloatUtil.ToString(Unk11));
            RelXml.ValueTag(sb, indent, "Unk12", FloatUtil.ToString(Unk12));
            RelXml.WriteRawArray(sb, Points, indent, "Points", "", RelXml.FormatVector2, 1);
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildUIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildVector4Attributes(node, "Unk02");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildUIntAttribute(node, "Unk04", "value");
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildFloatAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildFloatAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildFloatAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildFloatAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildFloatAttribute(node, "Unk11", "value");
            Unk12 = Xml.GetChildFloatAttribute(node, "Unk12", "value");
            Points = Xml.GetChildRawVector2Array(node, "Points");
            PointsCount = (uint)(Points?.Length ?? 0);
        }
    }
    [TC(typeof(EXP))] public class Dat151ShoreLineList : Dat151RelData
    {
        public uint ShoreLineCount { get; set; }
        public MetaHash[] ShoreLines { get; set; }

        public Dat151ShoreLineList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.ShoreLineList;
            TypeID = (byte)Type;
        }
        public Dat151ShoreLineList(RelData d, BinaryReader br) : base(d, br)
        {
            ShoreLineCount = br.ReadUInt32();
            var shorelines = new MetaHash[ShoreLineCount];
            for (int i = 0; i < ShoreLineCount; i++)
            {
                shorelines[i] = br.ReadUInt32();
            }
            ShoreLines = shorelines;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(ShoreLineCount);
            for (int i = 0; i < ShoreLineCount; i++)
            {
                bw.Write(ShoreLines[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteHashItemArray(sb, ShoreLines, indent, "ShoreLines");
        }
        public override void ReadXml(XmlNode node)
        {
            ShoreLines = XmlRel.ReadHashItemArray(node, "ShoreLines");
            ShoreLineCount = (uint)(ShoreLines?.Length ?? 0);
        }
        public override MetaHash[] GetGameHashes()
        {
            return ShoreLines;
        }
    }
    [TC(typeof(EXP))] public class Dat151RadioTrackEvents : Dat151RelData
    {
        public uint EventCount { get; set; }
        public EventData[] Events { get; set; }

        public struct EventData : IMetaXmlItem
        {
            public uint Time { get; set; }
            public uint Event { get; set; }

            public EventData(BinaryReader br)
            {
                Time = br.ReadUInt32();
                Event = br.ReadUInt32();
            }
            public void Write(BinaryWriter bw)
            {
                bw.Write(Time);
                bw.Write(Event);
            }
            public void WriteXml(StringBuilder sb, int indent)
            {
                RelXml.ValueTag(sb, indent, "Time", Time.ToString());
                RelXml.ValueTag(sb, indent, "Event", Event.ToString());
            }
            public void ReadXml(XmlNode node)
            {
                Time = Xml.GetChildUIntAttribute(node, "Time", "value");
                Event = Xml.GetChildUIntAttribute(node, "Event", "value");
            }

            public override string ToString()
            {
                return Time.ToString() + ": " + Event.ToString();
            }
        }

        public Dat151RadioTrackEvents(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.RadioTrackEvents;
            TypeID = (byte)Type;
        }
        public Dat151RadioTrackEvents(RelData d, BinaryReader br) : base(d, br)
        {
            EventCount = br.ReadUInt32();
            Events = new EventData[EventCount];
            for (int i = 0; i < EventCount; i++)
            {
                Events[i] = new EventData(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(EventCount);
            for (int i = 0; i < EventCount; i++)
            {
                Events[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, Events, indent, "Events");
        }
        public override void ReadXml(XmlNode node)
        {
            Events = XmlRel.ReadItemArray<EventData>(node, "Events");
            EventCount = (uint)(Events?.Length ?? 0);
        }
    }
    [TC(typeof(EXP))] public class Dat151VehicleEngineGranular : Dat151RelData
    {
        public FlagsUint Unk00 { get; set; }
        public int MasterVolume { get; set; }
        public MetaHash EngineAccel { get; set; }
        public MetaHash ExhaustAccel { get; set; }
        public int Unk04 { get; set; }
        public int Unk05 { get; set; }
        public int Unk06 { get; set; }
        public int Unk07 { get; set; }
        public int Unk08 { get; set; }
        public int Unk09 { get; set; }
        public int Unk10 { get; set; }
        public int Unk11 { get; set; }
        public int Unk12 { get; set; }
        public int EngineVolume { get; set; }
        public int ExhaustVolume { get; set; }
        public int EngineIdleVolume { get; set; }
        public int ExhaustIdleVolume { get; set; }
        public int Unk17 { get; set; }
        public int Unk18 { get; set; }
        public int EngineAccelVolume { get; set; }
        public int ExhaustAccelVolume { get; set; }
        public int Unk21 { get; set; }
        public float Unk22 { get; set; }
        public float Unk23 { get; set; }
        public float Unk24 { get; set; }
        public float Unk25 { get; set; }
        public float Unk26 { get; set; }
        public float Unk27 { get; set; }
        public float Unk28 { get; set; }
        public int Unk29 { get; set; }
        public int Unk30 { get; set; }
        public MetaHash EngineSubmix { get; set; }
        public MetaHash EngineSubmixPreset { get; set; }
        public MetaHash ExhaustSubmix { get; set; }
        public MetaHash ExhaustSubmixPreset { get; set; }
        public MetaHash EngineAccelNPC { get; set; }
        public MetaHash ExhaustAccelNPC { get; set; }
        public MetaHash LimiterPops { get; set; }
        public int Unk38 { get; set; }
        public int Unk39 { get; set; }
        public MetaHash Unk40 { get; set; }
        public MetaHash Unk41 { get; set; }
        public int Unk42 { get; set; }
        public int Unk43 { get; set; }
        public int Unk44 { get; set; }
        public MetaHash IdleSub { get; set; }
        public int Unk46 { get; set; }
        public int Unk47 { get; set; }
        public int Unk48 { get; set; }
        public int Unk49 { get; set; }
        public int Unk50 { get; set; }
        public int Unk51 { get; set; }
        public MetaHash EngineDamage { get; set; }
        public MetaHash LimiterPopsUpgraded { get; set; }
        public int Unk54 { get; set; }
        public int Unk55 { get; set; }
        public int Unk56 { get; set; }
        public int Unk57 { get; set; }
        public int Unk58 { get; set; }//OPTIONAL!? only include this and next if either nonzero?
        public float Unk59 { get; set; }//OPTIONAL!?

        public Dat151VehicleEngineGranular(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.VehicleEngineGranular;
            TypeID = (byte)Type;
        }
        public Dat151VehicleEngineGranular(RelData d, BinaryReader br) : base(d, br)
        {
            Unk00 = br.ReadUInt32();
            MasterVolume = br.ReadInt32();
            EngineAccel = br.ReadUInt32();
            ExhaustAccel = br.ReadUInt32();
            Unk04 = br.ReadInt32();
            Unk05 = br.ReadInt32();
            Unk06 = br.ReadInt32();
            Unk07 = br.ReadInt32();
            Unk08 = br.ReadInt32();
            Unk09 = br.ReadInt32();
            Unk10 = br.ReadInt32();
            Unk11 = br.ReadInt32();
            Unk12 = br.ReadInt32();
            EngineVolume = br.ReadInt32();
            ExhaustVolume = br.ReadInt32();
            EngineIdleVolume = br.ReadInt32();
            ExhaustIdleVolume = br.ReadInt32();
            Unk17 = br.ReadInt32();
            Unk18 = br.ReadInt32();
            EngineAccelVolume = br.ReadInt32();
            ExhaustAccelVolume = br.ReadInt32();
            Unk21 = br.ReadInt32();
            Unk22 = br.ReadSingle();
            Unk23 = br.ReadSingle();
            Unk24 = br.ReadSingle();
            Unk25 = br.ReadSingle();
            Unk26 = br.ReadSingle();
            Unk27 = br.ReadSingle();
            Unk28 = br.ReadSingle();
            Unk29 = br.ReadInt32();
            Unk30 = br.ReadInt32();
            EngineSubmix = br.ReadUInt32();
            EngineSubmixPreset = br.ReadUInt32();
            ExhaustSubmix = br.ReadUInt32();
            ExhaustSubmixPreset = br.ReadUInt32();
            EngineAccelNPC = br.ReadUInt32();
            ExhaustAccelNPC = br.ReadUInt32();
            LimiterPops = br.ReadUInt32();
            Unk38 = br.ReadInt32();
            Unk39 = br.ReadInt32();
            Unk40 = br.ReadUInt32();
            Unk41 = br.ReadUInt32();
            Unk42 = br.ReadInt32();
            Unk43 = br.ReadInt32();
            Unk44 = br.ReadInt32();
            IdleSub = br.ReadUInt32();
            Unk46 = br.ReadInt32();
            Unk47 = br.ReadInt32();
            Unk48 = br.ReadInt32();
            Unk49 = br.ReadInt32();
            Unk50 = br.ReadInt32();
            Unk51 = br.ReadInt32();
            EngineDamage = br.ReadUInt32();
            LimiterPopsUpgraded = br.ReadUInt32();
            Unk54 = br.ReadInt32();
            Unk55 = br.ReadInt32();
            Unk56 = br.ReadInt32();
            Unk57 = br.ReadInt32();



            switch (this.Unk00)
            {
                case 0xAAAAA905:
                case 0xAAAAA955:
                case 0xAAAAA954:
                case 0xAAAAA914:
                case 0xAAAAA904:
                case 0xAAAAA805:
                case 0xAAAAA915:
                case 0xAAAAA945:
                case 0xAAAAA815:
                case 0xAAAAA944:
                case 0xAAAAA854:
                    break;
                default:
                    break;
            }
            switch (this.Unk40)
            {
                case 1225003942:
                    break;
                default:
                    break;
            }
            switch (this.Unk41)
            {
                case 1479769906:
                    break;
                default:
                    break;
            }
            switch (this.Unk43)
            {
                case 5:
                case 3:
                case 4:
                case 2:
                case 6:
                case 1:
                    break;
                default:
                    break;
            }
            switch (this.Unk44)
            {
                case 2:
                case 1:
                case 3:
                case 4:
                    break;
                default:
                    break;
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            switch (bytesleft) //any other way to tell??
            {
                case 0:
                    break;
                case 8:
                    Unk58 = br.ReadInt32();
                    Unk59 = br.ReadSingle();
                    switch (Unk58)
                    {
                        case 1:
                        case 2:
                        case 0:
                            break;
                        default:
                            break;//no hit here
                    }
                    if ((Unk58 == 0) && (Unk59 == 0))
                    { }//no hit here
                    break;
                default:
                    break;//no hit here
            }

            if (bytesleft != 0)
            { }

            if (Unk04 != 0)
            { }
            if (Unk09 != 0)
            { }
            if (Unk10 != 0)
            { }
            if (Unk11 != 0)
            { }
            if (Unk12 != 0)
            { }
            if (Unk38 != 0)
            { }
            if (Unk39 != 0)
            { }
            if (Unk47 != 0)
            { }
            if (Unk48 != 0)
            { }
            if (Unk50 != 0)
            { }
            if (Unk51 != 0)
            { }


        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);
            bw.Write(Unk00);
            bw.Write(MasterVolume);
            bw.Write(EngineAccel);
            bw.Write(ExhaustAccel);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(EngineVolume);
            bw.Write(ExhaustVolume);
            bw.Write(EngineIdleVolume);
            bw.Write(ExhaustIdleVolume);
            bw.Write(Unk17);
            bw.Write(Unk18);
            bw.Write(EngineAccelVolume);
            bw.Write(ExhaustAccelVolume);
            bw.Write(Unk21);
            bw.Write(Unk22);
            bw.Write(Unk23);
            bw.Write(Unk24);
            bw.Write(Unk25);
            bw.Write(Unk26);
            bw.Write(Unk27);
            bw.Write(Unk28);
            bw.Write(Unk29);
            bw.Write(Unk30);
            bw.Write(EngineSubmix);
            bw.Write(EngineSubmixPreset);
            bw.Write(ExhaustSubmix);
            bw.Write(ExhaustSubmixPreset);
            bw.Write(EngineAccelNPC);
            bw.Write(ExhaustAccelNPC);
            bw.Write(LimiterPops);
            bw.Write(Unk38);
            bw.Write(Unk39);
            bw.Write(Unk40);
            bw.Write(Unk41);
            bw.Write(Unk42);
            bw.Write(Unk43);
            bw.Write(Unk44);
            bw.Write(IdleSub);
            bw.Write(Unk46);
            bw.Write(Unk47);
            bw.Write(Unk48);
            bw.Write(Unk49);
            bw.Write(Unk50);
            bw.Write(Unk51);
            bw.Write(EngineDamage);
            bw.Write(LimiterPopsUpgraded);
            bw.Write(Unk54);
            bw.Write(Unk55);
            bw.Write(Unk56);
            bw.Write(Unk57);
            if ((Unk58 != 0) || (Unk59 != 0))//how else to know?? seems hacky!
            {
                bw.Write(Unk58);
                bw.Write(Unk59);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk00", "0x" + Unk00.Hex);
            RelXml.ValueTag(sb, indent, "MasterVolume", MasterVolume.ToString());
            RelXml.StringTag(sb, indent, "EngineAccel", RelXml.HashString(EngineAccel));
            RelXml.StringTag(sb, indent, "ExhaustAccel", RelXml.HashString(ExhaustAccel));
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.ValueTag(sb, indent, "Unk06", Unk06.ToString());
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.ValueTag(sb, indent, "Unk11", Unk11.ToString());
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.ToString());
            RelXml.ValueTag(sb, indent, "EngineVolume", EngineVolume.ToString());
            RelXml.ValueTag(sb, indent, "ExhaustVolume", ExhaustVolume.ToString());
            RelXml.ValueTag(sb, indent, "EngineIdleVolume", EngineIdleVolume.ToString());
            RelXml.ValueTag(sb, indent, "ExhaustIdleVolume", ExhaustIdleVolume.ToString());
            RelXml.ValueTag(sb, indent, "Unk17", Unk17.ToString());
            RelXml.ValueTag(sb, indent, "Unk18", Unk18.ToString());
            RelXml.ValueTag(sb, indent, "EngineAccelVolume", EngineAccelVolume.ToString());
            RelXml.ValueTag(sb, indent, "ExhaustAccelVolume", ExhaustAccelVolume.ToString());
            RelXml.ValueTag(sb, indent, "Unk21", Unk21.ToString());
            RelXml.ValueTag(sb, indent, "Unk22", FloatUtil.ToString(Unk22));
            RelXml.ValueTag(sb, indent, "Unk23", FloatUtil.ToString(Unk23));
            RelXml.ValueTag(sb, indent, "Unk24", FloatUtil.ToString(Unk24));
            RelXml.ValueTag(sb, indent, "Unk25", FloatUtil.ToString(Unk25));
            RelXml.ValueTag(sb, indent, "Unk26", FloatUtil.ToString(Unk26));
            RelXml.ValueTag(sb, indent, "Unk27", FloatUtil.ToString(Unk27));
            RelXml.ValueTag(sb, indent, "Unk28", FloatUtil.ToString(Unk28));
            RelXml.ValueTag(sb, indent, "Unk29", Unk29.ToString());
            RelXml.ValueTag(sb, indent, "Unk30", Unk30.ToString());
            RelXml.StringTag(sb, indent, "EngineSubmix", RelXml.HashString(EngineSubmix));
            RelXml.StringTag(sb, indent, "EngineSubmixPreset", RelXml.HashString(EngineSubmixPreset));
            RelXml.StringTag(sb, indent, "ExhaustSubmix", RelXml.HashString(ExhaustSubmix));
            RelXml.StringTag(sb, indent, "ExhaustSubmixPreset", RelXml.HashString(ExhaustSubmixPreset));
            RelXml.StringTag(sb, indent, "EngineAccelNPC", RelXml.HashString(EngineAccelNPC));
            RelXml.StringTag(sb, indent, "ExhaustAccelNPC", RelXml.HashString(ExhaustAccelNPC));
            RelXml.StringTag(sb, indent, "LimiterPops", RelXml.HashString(LimiterPops));
            RelXml.ValueTag(sb, indent, "Unk38", Unk38.ToString());
            RelXml.ValueTag(sb, indent, "Unk39", Unk39.ToString());
            RelXml.StringTag(sb, indent, "Unk40", RelXml.HashString(Unk40));
            RelXml.StringTag(sb, indent, "Unk41", RelXml.HashString(Unk41));
            RelXml.ValueTag(sb, indent, "Unk42", Unk42.ToString());
            RelXml.ValueTag(sb, indent, "Unk43", Unk43.ToString());
            RelXml.ValueTag(sb, indent, "Unk44", Unk44.ToString());
            RelXml.StringTag(sb, indent, "IdleSub", RelXml.HashString(IdleSub));
            RelXml.ValueTag(sb, indent, "Unk46", Unk46.ToString());
            RelXml.ValueTag(sb, indent, "Unk47", Unk47.ToString());
            RelXml.ValueTag(sb, indent, "Unk48", Unk48.ToString());
            RelXml.ValueTag(sb, indent, "Unk49", Unk49.ToString());
            RelXml.ValueTag(sb, indent, "Unk50", Unk50.ToString());
            RelXml.ValueTag(sb, indent, "Unk51", Unk51.ToString());
            RelXml.StringTag(sb, indent, "EngineDamage", RelXml.HashString(EngineDamage));
            RelXml.StringTag(sb, indent, "LimiterPopsUpgraded", RelXml.HashString(LimiterPopsUpgraded));
            RelXml.ValueTag(sb, indent, "Unk54", Unk54.ToString());
            RelXml.ValueTag(sb, indent, "Unk55", Unk55.ToString());
            RelXml.ValueTag(sb, indent, "Unk56", Unk56.ToString());
            RelXml.ValueTag(sb, indent, "Unk57", Unk57.ToString());
            RelXml.ValueTag(sb, indent, "Unk58", Unk58.ToString());
            RelXml.ValueTag(sb, indent, "Unk59", FloatUtil.ToString(Unk59));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk00 = Xml.GetChildUIntAttribute(node, "Unk00", "value");
            MasterVolume = Xml.GetChildIntAttribute(node, "MasterVolume", "value");
            EngineAccel = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineAccel"));
            ExhaustAccel = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustAccel"));
            Unk04 = Xml.GetChildIntAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildIntAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildIntAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildIntAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildIntAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildIntAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildIntAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildIntAttribute(node, "Unk11", "value");
            Unk12 = Xml.GetChildIntAttribute(node, "Unk12", "value");
            EngineVolume = Xml.GetChildIntAttribute(node, "EngineVolume", "value");
            ExhaustVolume = Xml.GetChildIntAttribute(node, "ExhaustVolume", "value");
            EngineIdleVolume = Xml.GetChildIntAttribute(node, "EngineIdleVolume", "value");
            ExhaustIdleVolume = Xml.GetChildIntAttribute(node, "ExhaustIdleVolume", "value");
            Unk17 = Xml.GetChildIntAttribute(node, "Unk17", "value");
            Unk18 = Xml.GetChildIntAttribute(node, "Unk18", "value");
            EngineAccelVolume = Xml.GetChildIntAttribute(node, "EngineAccelVolume", "value");
            ExhaustAccelVolume = Xml.GetChildIntAttribute(node, "ExhaustAccelVolume", "value");
            Unk21 = Xml.GetChildIntAttribute(node, "Unk21", "value");
            Unk22 = Xml.GetChildFloatAttribute(node, "Unk22", "value");
            Unk23 = Xml.GetChildFloatAttribute(node, "Unk23", "value");
            Unk24 = Xml.GetChildFloatAttribute(node, "Unk24", "value");
            Unk25 = Xml.GetChildFloatAttribute(node, "Unk25", "value");
            Unk26 = Xml.GetChildFloatAttribute(node, "Unk26", "value");
            Unk27 = Xml.GetChildFloatAttribute(node, "Unk27", "value");
            Unk28 = Xml.GetChildFloatAttribute(node, "Unk28", "value");
            Unk29 = Xml.GetChildIntAttribute(node, "Unk29", "value");
            Unk30 = Xml.GetChildIntAttribute(node, "Unk30", "value");
            EngineSubmix = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineSubmix"));
            EngineSubmixPreset = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineSubmixPreset"));
            ExhaustSubmix = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustSubmix"));
            ExhaustSubmixPreset = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustSubmixPreset"));
            EngineAccelNPC = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineAccelNPC"));
            ExhaustAccelNPC = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustAccelNPC"));
            LimiterPops = XmlRel.GetHash(Xml.GetChildInnerText(node, "LimiterPops"));
            Unk38 = Xml.GetChildIntAttribute(node, "Unk38", "value");
            Unk39 = Xml.GetChildIntAttribute(node, "Unk39", "value");
            Unk40 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk40"));
            Unk41 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk41"));
            Unk42 = Xml.GetChildIntAttribute(node, "Unk42", "value");
            Unk43 = Xml.GetChildIntAttribute(node, "Unk43", "value");
            Unk44 = Xml.GetChildIntAttribute(node, "Unk44", "value");
            IdleSub = XmlRel.GetHash(Xml.GetChildInnerText(node, "IdleSub"));
            Unk46 = Xml.GetChildIntAttribute(node, "Unk46", "value");
            Unk47 = Xml.GetChildIntAttribute(node, "Unk47", "value");
            Unk48 = Xml.GetChildIntAttribute(node, "Unk48", "value");
            Unk49 = Xml.GetChildIntAttribute(node, "Unk49", "value");
            Unk50 = Xml.GetChildIntAttribute(node, "Unk50", "value");
            Unk51 = Xml.GetChildIntAttribute(node, "Unk51", "value");
            EngineDamage = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineDamage"));
            LimiterPopsUpgraded = XmlRel.GetHash(Xml.GetChildInnerText(node, "LimiterPopsUpgraded"));
            Unk54 = Xml.GetChildIntAttribute(node, "Unk54", "value");
            Unk55 = Xml.GetChildIntAttribute(node, "Unk55", "value");
            Unk56 = Xml.GetChildIntAttribute(node, "Unk56", "value");
            Unk57 = Xml.GetChildIntAttribute(node, "Unk57", "value");
            Unk58 = Xml.GetChildIntAttribute(node, "Unk58", "value");
            Unk59 = Xml.GetChildFloatAttribute(node, "Unk59", "value");
        }
        public override MetaHash[] GetSynthHashes()
        {
            return new[] { EngineSubmix, EngineSubmixPreset, ExhaustSubmix, ExhaustSubmixPreset };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { EngineAccel, ExhaustAccel, EngineAccelNPC, ExhaustAccelNPC, LimiterPops, Unk40, Unk41, IdleSub, EngineDamage, LimiterPopsUpgraded };
        }
    }
    [TC(typeof(EXP))] public class Dat151Vehicle : Dat151RelData
    {
        public FlagsUint Unk00 { get; set; } //2432719400   0x91005A28
        public MetaHash Engine { get; set; }
        public MetaHash EngineGranular { get; set; }
        public MetaHash Horns { get; set; }
        public MetaHash DoorOpen { get; set; }
        public MetaHash DoorClose { get; set; }
        public MetaHash TrunkOpen { get; set; }
        public MetaHash TrunkClose { get; set; }
        public MetaHash Unk08 { get; set; }
        public float Unk09 { get; set; }
        public MetaHash SuspensionUp { get; set; }
        public MetaHash SuspensionDown { get; set; }
        public float Unk12 { get; set; }
        public float Unk13 { get; set; }
        public MetaHash Collision { get; set; }
        public int Unk15 { get; set; }
        public int Unk16 { get; set; }
        public int Unk17 { get; set; }
        public MetaHash ScannerParams { get; set; }
        public MetaHash JumpLandIntact { get; set; }
        public MetaHash JumpLandLoose { get; set; }
        public int Unk21 { get; set; }
        public int Unk22 { get; set; }
        public FlagsUint RadioFlags { get; set; }
        public MetaHash IndicatorOn { get; set; }
        public MetaHash IndicatorOff { get; set; }
        public MetaHash Handbrake { get; set; }
        public ushort Unk27 { get; set; }
        public ushort Unk28 { get; set; }
        public MetaHash ParkingTones { get; set; }
        public MetaHash Unk29 { get; set; }
        public MetaHash Unk30 { get; set; }
        public MetaHash Unk31 { get; set; }
        public MetaHash Fire { get; set; }
        public MetaHash StartupSequence { get; set; }// 0xB807DF3E
        public MetaHash Unk34 { get; set; }//  0xE38FCF16
        public MetaHash Unk35 { get; set; }
        public MetaHash Unk36 { get; set; }
        public float Unk37 { get; set; }
        public float Unk38 { get; set; }
        public MetaHash Unk39 { get; set; }
        public int Unk40 { get; set; }
        public MetaHash Sirens { get; set; }// 0x49DF3CF8   0x8E53EC78
        public int Unk42 { get; set; }
        public int Unk43 { get; set; }
        public int Unk44 { get; set; }
        public MetaHash Unk45 { get; set; }
        public MetaHash Unk46 { get; set; }
        public MetaHash ForkSounds { get; set; }//  0x83FC62DA
        public MetaHash TurretSounds { get; set; }
        public int Unk49 { get; set; }
        public MetaHash ScoopSounds { get; set; }// 0x65A95A8B, 0x85439DAD
        public MetaHash TowArmSounds { get; set; }// 0x6213618E, 0x990D0483
        public int Unk52 { get; set; }
        public MetaHash ElectricEngine { get; set; }// 0x04D73241, 0x7F471776
        public float Unk54 { get; set; }
        public MetaHash ReverseWarning { get; set; }
        public int EngineHealth { get; set; }
        public MetaHash VehicleMaster { get; set; }//not sure what this one does?
        public MetaHash ShutdownBeep { get; set; }
        public float Unk59 { get; set; }
        public int Unk60 { get; set; }
        public float Unk61 { get; set; }
        public int Unk62 { get; set; }
        public MetaHash Unk63 { get; set; }
        public int Unk64 { get; set; }
        public ushort Unk65 { get; set; }
        public ushort Unk66 { get; set; }
        public MetaHash ConvertibleRoof { get; set; }
        public MetaHash Unk68 { get; set; }
        public MetaHash InteriorTones { get; set; }
        public int Unk70 { get; set; }
        public MetaHash Unk71 { get; set; }
        public MetaHash Unk72 { get; set; }

        public Dat151Vehicle(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Vehicle;
            TypeID = (byte)Type;
        }
        public Dat151Vehicle(RelData d, BinaryReader br) : base(d, br)
        {
            Unk00 = br.ReadUInt32(); //2432719400   0x91005A28
            Engine = br.ReadUInt32();
            EngineGranular = br.ReadUInt32();
            Horns = br.ReadUInt32();
            DoorOpen = br.ReadUInt32();
            DoorClose = br.ReadUInt32();
            TrunkOpen = br.ReadUInt32();
            TrunkClose = br.ReadUInt32();
            Unk08 = br.ReadUInt32();
            Unk09 = br.ReadSingle();
            SuspensionUp = br.ReadUInt32();
            SuspensionDown = br.ReadUInt32();
            Unk12 = br.ReadSingle();
            Unk13 = br.ReadSingle();
            Collision = br.ReadUInt32();//split? 0x00C2FB47..
            Unk15 = br.ReadInt32();
            Unk16 = br.ReadInt32();
            Unk17 = br.ReadInt32();
            ScannerParams = br.ReadUInt32();
            JumpLandIntact = br.ReadUInt32();
            JumpLandLoose = br.ReadUInt32();
            Unk21 = br.ReadInt32();
            Unk22 = br.ReadInt32();
            RadioFlags = br.ReadUInt32();
            IndicatorOn = br.ReadUInt32();
            IndicatorOff = br.ReadUInt32();
            Handbrake = br.ReadUInt32();
            Unk27 = br.ReadUInt16();
            Unk28 = br.ReadUInt16();
            ParkingTones = br.ReadUInt32();
            Unk29 = br.ReadUInt32();
            Unk30 = br.ReadUInt32();
            Unk31 = br.ReadUInt32();
            Fire = br.ReadUInt32();
            StartupSequence = br.ReadUInt32();//flags??  0xB807DF3E
            Unk34 = br.ReadUInt32();//flags??  0xE38FCF16
            Unk35 = br.ReadUInt32();
            Unk36 = br.ReadUInt32();
            Unk37 = br.ReadSingle();
            Unk38 = br.ReadSingle();
            Unk39 = br.ReadUInt32();
            Unk40 = br.ReadInt32();
            Sirens = br.ReadUInt32();//flags? 0x49DF3CF8   0x8E53EC78
            Unk42 = br.ReadInt32();
            Unk43 = br.ReadInt32();
            Unk44 = br.ReadInt32();
            Unk45 = br.ReadUInt32();
            Unk46 = br.ReadUInt32();
            ForkSounds = br.ReadUInt32();//flags?  0x83FC62DA
            TurretSounds = br.ReadUInt32();
            Unk49 = br.ReadInt32();
            ScoopSounds = br.ReadUInt32();//flags? 0x65A95A8B, 0x85439DAD
            TowArmSounds = br.ReadUInt32();//flags? 0x6213618E, 0x990D0483
            Unk52 = br.ReadInt32();
            ElectricEngine = br.ReadUInt32();//flags?  0x04D73241, 0x7F471776
            Unk54 = br.ReadSingle();
            ReverseWarning = br.ReadUInt32();
            EngineHealth = br.ReadInt32();
            VehicleMaster = br.ReadUInt32();
            ShutdownBeep = br.ReadUInt32();
            Unk59 = br.ReadSingle();
            Unk60 = br.ReadInt32();
            Unk61 = br.ReadSingle();
            Unk62 = br.ReadInt32();



            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            switch (bytesleft) //any other way to tell..?
            {
                case 0:
                    break;
                case 4:
                    Unk63 = br.ReadUInt32();//flags??  0xE38FCF16
                    if (Unk63 == 0)
                    { }
                    break;
                case 36:
                    Unk63 = br.ReadUInt32();//flags??  0xE38FCF16
                    Unk64 = br.ReadInt32();
                    Unk65 = br.ReadUInt16();
                    Unk66 = br.ReadUInt16();
                    ConvertibleRoof = br.ReadUInt32();//flags?  0x536F6CAC
                    Unk68 = br.ReadUInt32();//flags??  0xE38FCF16
                    InteriorTones = br.ReadUInt32();//flags?  0x7C9B8D8C
                    Unk70 = br.ReadInt32();
                    Unk71 = br.ReadUInt32();//flags??  0xE38FCF16
                    Unk72 = br.ReadUInt32();//flags??  0xE38FCF16
                    if (Unk70 != 0)
                    { }
                    if (Unk68 == 0)
                    { }
                    if (Unk71 == 0)
                    { }
                    if (Unk72 == 0)
                    { }

                    break;
                default:
                    break;
            }
            if (bytesleft != 0)
            { }



            if (Unk15 != 0)
            { }
            if (Unk16 != 0)
            { }
            if (Unk17 != 0)
            { }
            if (Unk40 != 0)
            { }
            if (Unk42 != 0)
            { }
            if (Unk43 != 0)
            { }
            if (Unk44 != 0)
            { }

            switch (Unk21)
            {
                case 31:
                case 0:
                    break;
                default:
                    break;
            }
            switch (Unk22)
            {
                case 36:
                case 100:
                case 1:
                    break;
                default:
                    break;
            }
            switch (Unk49)
            {
                case 8:
                case 5:
                case 3:
                case 1:
                case 4:
                case 0:
                case 6:
                case 7:
                    break;
                default:
                    break;
            }
            switch (EngineHealth)
            {
                case 2:
                case 3:
                case 0:
                case 1:
                    break;
                default:
                    break;
            }

        }
        public override void Write(BinaryWriter bw)
        {
            //base.Write(bw);
            //return;

            WriteTypeAndOffset(bw);

            bw.Write(Unk00); //2432719400   0x91005A28
            bw.Write(Engine);
            bw.Write(EngineGranular);
            bw.Write(Horns);
            bw.Write(DoorOpen);
            bw.Write(DoorClose);
            bw.Write(TrunkOpen);
            bw.Write(TrunkClose);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(SuspensionUp);
            bw.Write(SuspensionDown);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Collision);//split? 0x00C2FB47..
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(ScannerParams);
            bw.Write(JumpLandIntact);
            bw.Write(JumpLandLoose);
            bw.Write(Unk21);
            bw.Write(Unk22);
            bw.Write(RadioFlags);
            bw.Write(IndicatorOn);
            bw.Write(IndicatorOff);
            bw.Write(Handbrake);
            bw.Write(Unk27);
            bw.Write(Unk28);
            bw.Write(ParkingTones);
            bw.Write(Unk29);
            bw.Write(Unk30);
            bw.Write(Unk31);
            bw.Write(Fire);
            bw.Write(StartupSequence);//flags??  0xB807DF3E
            bw.Write(Unk34);//flags??  0xE38FCF16
            bw.Write(Unk35);
            bw.Write(Unk36);
            bw.Write(Unk37);
            bw.Write(Unk38);
            bw.Write(Unk39);
            bw.Write(Unk40);
            bw.Write(Sirens);//flags? 0x49DF3CF8   0x8E53EC78
            bw.Write(Unk42);
            bw.Write(Unk43);
            bw.Write(Unk44);
            bw.Write(Unk45);
            bw.Write(Unk46);
            bw.Write(ForkSounds);//flags?  0x83FC62DA
            bw.Write(TurretSounds);
            bw.Write(Unk49);
            bw.Write(ScoopSounds);//flags? 0x65A95A8B, 0x85439DAD
            bw.Write(TowArmSounds);//flags? 0x6213618E, 0x990D0483
            bw.Write(Unk52);
            bw.Write(ElectricEngine);//flags?  0x04D73241, 0x7F471776
            bw.Write(Unk54);
            bw.Write(ReverseWarning);
            bw.Write(EngineHealth);
            bw.Write(VehicleMaster);
            bw.Write(ShutdownBeep);
            bw.Write(Unk59);
            bw.Write(Unk60);
            bw.Write(Unk61);
            bw.Write(Unk62);

            if (Unk63 != 0)//any better way?
            {
                bw.Write(Unk63);

                if ((Unk68 != 0)||(Unk71 != 0) ||(Unk72 != 0))//any better way?
                {
                    bw.Write(Unk64);
                    bw.Write(Unk65);
                    bw.Write(Unk66);
                    bw.Write(ConvertibleRoof);//flags?  0x536F6CAC
                    bw.Write(Unk68);//flags??  0xE38FCF16
                    bw.Write(InteriorTones);//flags?  0x7C9B8D8C
                    bw.Write(Unk70);
                    bw.Write(Unk71);//flags??  0xE38FCF16
                    bw.Write(Unk72);//flags??  0xE38FCF16
                }
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk00", "0x" + Unk00.Hex);
            RelXml.StringTag(sb, indent, "Engine", RelXml.HashString(Engine));
            RelXml.StringTag(sb, indent, "EngineGranular", RelXml.HashString(EngineGranular));
            RelXml.StringTag(sb, indent, "Horns", RelXml.HashString(Horns));
            RelXml.StringTag(sb, indent, "DoorOpen", RelXml.HashString(DoorOpen));
            RelXml.StringTag(sb, indent, "DoorClose", RelXml.HashString(DoorClose));
            RelXml.StringTag(sb, indent, "TrunkOpen", RelXml.HashString(TrunkOpen));
            RelXml.StringTag(sb, indent, "TrunkClose", RelXml.HashString(TrunkClose));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.ValueTag(sb, indent, "Unk09", FloatUtil.ToString(Unk09));
            RelXml.StringTag(sb, indent, "SuspensionUp", RelXml.HashString(SuspensionUp));
            RelXml.StringTag(sb, indent, "SuspensionDown", RelXml.HashString(SuspensionDown));
            RelXml.ValueTag(sb, indent, "Unk12", FloatUtil.ToString(Unk12));
            RelXml.ValueTag(sb, indent, "Unk13", FloatUtil.ToString(Unk13));
            RelXml.StringTag(sb, indent, "Collision", RelXml.HashString(Collision));
            RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.ValueTag(sb, indent, "Unk17", Unk17.ToString());
            RelXml.StringTag(sb, indent, "ScannerParams", RelXml.HashString(ScannerParams));
            RelXml.StringTag(sb, indent, "JumpLandIntact", RelXml.HashString(JumpLandIntact));
            RelXml.StringTag(sb, indent, "JumpLandLoose", RelXml.HashString(JumpLandLoose));
            RelXml.ValueTag(sb, indent, "Unk21", Unk21.ToString());
            RelXml.ValueTag(sb, indent, "Unk22", Unk22.ToString());
            RelXml.ValueTag(sb, indent, "RadioFlags", "0x" + RadioFlags.Hex);
            RelXml.StringTag(sb, indent, "IndicatorOn", RelXml.HashString(IndicatorOn));
            RelXml.StringTag(sb, indent, "IndicatorOff", RelXml.HashString(IndicatorOff));
            RelXml.StringTag(sb, indent, "Handbrake", RelXml.HashString(Handbrake));
            RelXml.ValueTag(sb, indent, "Unk27", Unk27.ToString());
            RelXml.ValueTag(sb, indent, "Unk28", Unk28.ToString());
            RelXml.StringTag(sb, indent, "ParkingTones", RelXml.HashString(ParkingTones));
            RelXml.StringTag(sb, indent, "Unk29", RelXml.HashString(Unk29));
            RelXml.StringTag(sb, indent, "Unk30", RelXml.HashString(Unk30));
            RelXml.StringTag(sb, indent, "Unk31", RelXml.HashString(Unk31));
            RelXml.StringTag(sb, indent, "Fire", RelXml.HashString(Fire));
            RelXml.StringTag(sb, indent, "StartupSequence", RelXml.HashString(StartupSequence));
            RelXml.StringTag(sb, indent, "Unk34", RelXml.HashString(Unk34));
            RelXml.StringTag(sb, indent, "Unk35", RelXml.HashString(Unk35));
            RelXml.StringTag(sb, indent, "Unk36", RelXml.HashString(Unk36));
            RelXml.ValueTag(sb, indent, "Unk37", FloatUtil.ToString(Unk37));
            RelXml.ValueTag(sb, indent, "Unk38", FloatUtil.ToString(Unk38));
            RelXml.StringTag(sb, indent, "Unk39", RelXml.HashString(Unk39));
            RelXml.ValueTag(sb, indent, "Unk40", Unk40.ToString());
            RelXml.StringTag(sb, indent, "Sirens", RelXml.HashString(Sirens));
            RelXml.ValueTag(sb, indent, "Unk42", Unk42.ToString());
            RelXml.ValueTag(sb, indent, "Unk43", Unk43.ToString());
            RelXml.ValueTag(sb, indent, "Unk44", Unk44.ToString());
            RelXml.StringTag(sb, indent, "Unk45", RelXml.HashString(Unk45));
            RelXml.StringTag(sb, indent, "Unk46", RelXml.HashString(Unk46));
            RelXml.StringTag(sb, indent, "ForkSounds", RelXml.HashString(ForkSounds));
            RelXml.StringTag(sb, indent, "TurretSounds", RelXml.HashString(TurretSounds));
            RelXml.ValueTag(sb, indent, "Unk49", Unk49.ToString());
            RelXml.StringTag(sb, indent, "ScoopSounds", RelXml.HashString(ScoopSounds));
            RelXml.StringTag(sb, indent, "TowArmSounds", RelXml.HashString(TowArmSounds));
            RelXml.ValueTag(sb, indent, "Unk52", Unk52.ToString());
            RelXml.StringTag(sb, indent, "ElectricEngine", RelXml.HashString(ElectricEngine));
            RelXml.ValueTag(sb, indent, "Unk54", FloatUtil.ToString(Unk54));
            RelXml.StringTag(sb, indent, "ReverseWarning", RelXml.HashString(ReverseWarning));
            RelXml.ValueTag(sb, indent, "EngineHealth", EngineHealth.ToString());
            RelXml.StringTag(sb, indent, "VehicleMaster", RelXml.HashString(VehicleMaster));
            RelXml.StringTag(sb, indent, "ShutdownBeep", RelXml.HashString(ShutdownBeep));
            RelXml.ValueTag(sb, indent, "Unk59", FloatUtil.ToString(Unk59));
            RelXml.ValueTag(sb, indent, "Unk60", Unk60.ToString());
            RelXml.ValueTag(sb, indent, "Unk61", FloatUtil.ToString(Unk61));
            RelXml.ValueTag(sb, indent, "Unk62", Unk62.ToString());
            RelXml.StringTag(sb, indent, "Unk63", RelXml.HashString(Unk63));
            RelXml.ValueTag(sb, indent, "Unk64", Unk64.ToString());
            RelXml.ValueTag(sb, indent, "Unk65", Unk65.ToString());
            RelXml.ValueTag(sb, indent, "Unk66", Unk66.ToString());
            RelXml.StringTag(sb, indent, "ConvertibleRoof", RelXml.HashString(ConvertibleRoof));
            RelXml.StringTag(sb, indent, "Unk68", RelXml.HashString(Unk68));
            RelXml.StringTag(sb, indent, "InteriorTones", RelXml.HashString(InteriorTones));
            RelXml.ValueTag(sb, indent, "Unk70", Unk70.ToString());
            RelXml.StringTag(sb, indent, "Unk71", RelXml.HashString(Unk71));
            RelXml.StringTag(sb, indent, "Unk72", RelXml.HashString(Unk72));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk00 = Xml.GetChildUIntAttribute(node, "Unk00", "value");
            Engine = XmlRel.GetHash(Xml.GetChildInnerText(node, "Engine"));
            EngineGranular = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineGranular"));
            Horns = XmlRel.GetHash(Xml.GetChildInnerText(node, "Horns"));
            DoorOpen = XmlRel.GetHash(Xml.GetChildInnerText(node, "DoorOpen"));
            DoorClose = XmlRel.GetHash(Xml.GetChildInnerText(node, "DoorClose"));
            TrunkOpen = XmlRel.GetHash(Xml.GetChildInnerText(node, "TrunkOpen"));
            TrunkClose = XmlRel.GetHash(Xml.GetChildInnerText(node, "TrunkClose"));
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = Xml.GetChildFloatAttribute(node, "Unk09", "value");
            SuspensionUp = XmlRel.GetHash(Xml.GetChildInnerText(node, "SuspensionUp"));
            SuspensionDown = XmlRel.GetHash(Xml.GetChildInnerText(node, "SuspensionDown"));
            Unk12 = Xml.GetChildFloatAttribute(node, "Unk12", "value");
            Unk13 = Xml.GetChildFloatAttribute(node, "Unk13", "value");
            Collision = XmlRel.GetHash(Xml.GetChildInnerText(node, "Collision"));
            Unk15 = Xml.GetChildIntAttribute(node, "Unk15", "value");
            Unk16 = Xml.GetChildIntAttribute(node, "Unk16", "value");
            Unk17 = Xml.GetChildIntAttribute(node, "Unk17", "value");
            ScannerParams = XmlRel.GetHash(Xml.GetChildInnerText(node, "ScannerParams"));
            JumpLandIntact = XmlRel.GetHash(Xml.GetChildInnerText(node, "JumpLandIntact"));
            JumpLandLoose = XmlRel.GetHash(Xml.GetChildInnerText(node, "JumpLandLoose"));
            Unk21 = Xml.GetChildIntAttribute(node, "Unk21", "value");
            Unk22 = Xml.GetChildIntAttribute(node, "Unk22", "value");
            RadioFlags = Xml.GetChildUIntAttribute(node, "RadioFlags", "value");
            IndicatorOn = XmlRel.GetHash(Xml.GetChildInnerText(node, "IndicatorOn"));
            IndicatorOff = XmlRel.GetHash(Xml.GetChildInnerText(node, "IndicatorOff"));
            Handbrake = XmlRel.GetHash(Xml.GetChildInnerText(node, "Handbrake"));
            Unk27 = (ushort)Xml.GetChildUIntAttribute(node, "Unk27", "value");
            Unk28 = (ushort)Xml.GetChildUIntAttribute(node, "Unk28", "value");
            ParkingTones = XmlRel.GetHash(Xml.GetChildInnerText(node, "ParkingTones"));
            Unk29 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk29"));
            Unk30 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk30"));
            Unk31 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk31"));
            Fire = XmlRel.GetHash(Xml.GetChildInnerText(node, "Fire"));
            StartupSequence = XmlRel.GetHash(Xml.GetChildInnerText(node, "StartupSequence"));
            Unk34 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk34"));
            Unk35 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk35"));
            Unk36 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk36"));
            Unk37 = Xml.GetChildFloatAttribute(node, "Unk37", "value");
            Unk38 = Xml.GetChildFloatAttribute(node, "Unk38", "value");
            Unk39 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk39"));
            Unk40 = Xml.GetChildIntAttribute(node, "Unk40", "value");
            Sirens = XmlRel.GetHash(Xml.GetChildInnerText(node, "Sirens"));
            Unk42 = Xml.GetChildIntAttribute(node, "Unk42", "value");
            Unk43 = Xml.GetChildIntAttribute(node, "Unk43", "value");
            Unk44 = Xml.GetChildIntAttribute(node, "Unk44", "value");
            Unk45 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk45"));
            Unk46 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk46"));
            ForkSounds = XmlRel.GetHash(Xml.GetChildInnerText(node, "ForkSounds"));
            TurretSounds = XmlRel.GetHash(Xml.GetChildInnerText(node, "TurretSounds"));
            Unk49 = Xml.GetChildIntAttribute(node, "Unk49", "value");
            ScoopSounds = XmlRel.GetHash(Xml.GetChildInnerText(node, "ScoopSounds"));
            TowArmSounds = XmlRel.GetHash(Xml.GetChildInnerText(node, "TowArmSounds"));
            Unk52 = Xml.GetChildIntAttribute(node, "Unk52", "value");
            ElectricEngine = XmlRel.GetHash(Xml.GetChildInnerText(node, "ElectricEngine"));
            Unk54 = Xml.GetChildFloatAttribute(node, "Unk54", "value");
            ReverseWarning = XmlRel.GetHash(Xml.GetChildInnerText(node, "ReverseWarning"));
            EngineHealth = Xml.GetChildIntAttribute(node, "EngineHealth", "value");
            VehicleMaster = XmlRel.GetHash(Xml.GetChildInnerText(node, "VehicleMaster"));
            ShutdownBeep = XmlRel.GetHash(Xml.GetChildInnerText(node, "ShutdownBeep"));
            Unk59 = Xml.GetChildFloatAttribute(node, "Unk59", "value");
            Unk60 = Xml.GetChildIntAttribute(node, "Unk60", "value");
            Unk61 = Xml.GetChildFloatAttribute(node, "Unk61", "value");
            Unk62 = Xml.GetChildIntAttribute(node, "Unk62", "value");
            Unk63 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk63"));
            Unk64 = Xml.GetChildIntAttribute(node, "Unk64", "value");
            Unk65 = (ushort)Xml.GetChildUIntAttribute(node, "Unk65", "value");
            Unk66 = (ushort)Xml.GetChildUIntAttribute(node, "Unk66", "value");
            ConvertibleRoof = XmlRel.GetHash(Xml.GetChildInnerText(node, "ConvertibleRoof"));
            Unk68 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk68"));
            InteriorTones = XmlRel.GetHash(Xml.GetChildInnerText(node, "InteriorTones"));
            Unk70 = Xml.GetChildIntAttribute(node, "Unk70", "value");
            Unk71 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk71"));
            Unk72 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk72"));
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Horns, DoorOpen, DoorClose, TrunkOpen, TrunkClose, Unk08, SuspensionUp, SuspensionDown, JumpLandIntact, JumpLandLoose,
                IndicatorOn, IndicatorOff, Handbrake, ParkingTones, Unk29, Unk30, Unk31, Fire, StartupSequence, Unk34, Unk35, Unk36, Unk39,
                Sirens, Unk45, Unk46, ForkSounds, TurretSounds, ScoopSounds, TowArmSounds, ReverseWarning, VehicleMaster, ShutdownBeep,
                Unk63, ConvertibleRoof, Unk68, InteriorTones, Unk71, Unk72 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { Engine, EngineGranular, Collision, ScannerParams, ElectricEngine };
        }
    }
    [TC(typeof(EXP))] public class Dat151VehicleEngine : Dat151RelData
    {
        public int MasterVolume { get; set; }
        public int EngineLowVolume { get; set; }
        public int EngineHighVolume { get; set; }
        public int EngineNPCVolume { get; set; }
        public MetaHash EngineLow { get; set; }
        public MetaHash EngineHigh { get; set; }
        public MetaHash ExhaustLow { get; set; }
        public MetaHash ExhaustHigh { get; set; }
        public MetaHash RevsOff { get; set; }
        public int Unk09 { get; set; }
        public int Unk10 { get; set; }
        public MetaHash EngineIdleLoop { get; set; }
        public MetaHash ExhaustIdleLoop { get; set; }
        public int Unk13 { get; set; }
        public int Unk14 { get; set; }
        public MetaHash AirIntake { get; set; }
        public int Unk16 { get; set; }
        public int Unk17 { get; set; }
        public MetaHash Turbo { get; set; }
        public int Unk19 { get; set; }
        public int Unk20 { get; set; }
        public MetaHash DumpValve { get; set; }
        public int Unk22 { get; set; }
        public int Unk23 { get; set; }
        public MetaHash Transmission { get; set; }
        public int Unk25 { get; set; }
        public int Unk26 { get; set; }
        public int Unk27 { get; set; }
        public MetaHash Ignition { get; set; }
        public MetaHash ShutDown { get; set; }
        public MetaHash EngineCoolingFan { get; set; }
        public MetaHash ExhaustPops { get; set; }
        public MetaHash DistantStart { get; set; }
        public int Unk33 { get; set; }
        public int GearStickVolume { get; set; }
        public MetaHash StartupMaster { get; set; }
        public MetaHash EngineSubmix { get; set; }
        public MetaHash EngineSubmixPreset { get; set; }
        public MetaHash ExhaustSubmix { get; set; }
        public MetaHash ExhaustSubmixPreset { get; set; }
        public MetaHash Unk40 { get; set; }
        public MetaHash Unk41 { get; set; }
        public int Unk42 { get; set; }
        public MetaHash GearShiftInteriorUpgraded { get; set; }
        public MetaHash GearShiftExteriorUpgraded { get; set; }
        public int Unk45 { get; set; }
        public int Unk46 { get; set; }
        public int Unk47 { get; set; }
        public int Unk48 { get; set; }
        public int Unk49 { get; set; }
        public int Unk50 { get; set; }
        public MetaHash DumpValveUpgraded { get; set; }
        public int Unk52 { get; set; }
        public MetaHash TransmissionUpgraded { get; set; }
        public MetaHash TurboUpgraded { get; set; }
        public MetaHash AirIntakeUpgraded { get; set; }
        public MetaHash ExhaustPopsUpgraded { get; set; }

        public Dat151VehicleEngine(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.VehicleEngine;
            TypeID = (byte)Type;
        }
        public Dat151VehicleEngine(RelData d, BinaryReader br) : base(d, br)
        {
            MasterVolume = br.ReadInt32();
            EngineLowVolume = br.ReadInt32();
            EngineHighVolume = br.ReadInt32();
            EngineNPCVolume = br.ReadInt32();
            EngineLow = br.ReadUInt32();
            EngineHigh = br.ReadUInt32();
            ExhaustLow = br.ReadUInt32();
            ExhaustHigh = br.ReadUInt32();
            RevsOff = br.ReadUInt32();
            Unk09 = br.ReadInt32();
            Unk10 = br.ReadInt32();
            EngineIdleLoop = br.ReadUInt32();
            ExhaustIdleLoop = br.ReadUInt32();
            Unk13 = br.ReadInt32();
            Unk14 = br.ReadInt32();
            AirIntake = br.ReadUInt32();
            Unk16 = br.ReadInt32();
            Unk17 = br.ReadInt32();
            Turbo = br.ReadUInt32();
            Unk19 = br.ReadInt32();
            Unk20 = br.ReadInt32();
            DumpValve = br.ReadUInt32();
            Unk22 = br.ReadInt32();
            Unk23 = br.ReadInt32();
            Transmission = br.ReadUInt32();
            Unk25 = br.ReadInt32();
            Unk26 = br.ReadInt32();
            Unk27 = br.ReadInt32();
            Ignition = br.ReadUInt32();
            ShutDown = br.ReadUInt32();
            EngineCoolingFan = br.ReadUInt32();
            ExhaustPops = br.ReadUInt32();
            DistantStart = br.ReadUInt32();
            Unk33 = br.ReadInt32();
            GearStickVolume = br.ReadInt32();
            StartupMaster = br.ReadUInt32();
            EngineSubmix = br.ReadUInt32();
            EngineSubmixPreset = br.ReadUInt32();
            ExhaustSubmix = br.ReadUInt32();
            ExhaustSubmixPreset = br.ReadUInt32();//flags? separate?
            Unk40 = br.ReadUInt32();
            Unk41 = br.ReadUInt32();
            Unk42 = br.ReadInt32();
            GearShiftInteriorUpgraded = br.ReadUInt32();
            GearShiftExteriorUpgraded = br.ReadUInt32();//flags? separate?
            Unk45 = br.ReadInt32();
            Unk46 = br.ReadInt32();
            Unk47 = br.ReadInt32();
            Unk48 = br.ReadInt32();
            Unk49 = br.ReadInt32();
            Unk50 = br.ReadInt32();
            DumpValveUpgraded = br.ReadUInt32();//float?
            Unk52 = br.ReadInt32();
            TransmissionUpgraded = br.ReadUInt32();
            TurboUpgraded = br.ReadUInt32();
            AirIntakeUpgraded = br.ReadUInt32();
            ExhaustPopsUpgraded = br.ReadUInt32();


            if (Unk46 != 0)
            { }
            if (Unk47 != 0)
            { }
            if (Unk49 != 0)
            { }
            if (Unk50 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }

        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(MasterVolume);
            bw.Write(EngineLowVolume);
            bw.Write(EngineHighVolume);
            bw.Write(EngineNPCVolume);
            bw.Write(EngineLow);
            bw.Write(EngineHigh);
            bw.Write(ExhaustLow);
            bw.Write(ExhaustHigh);
            bw.Write(RevsOff);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(EngineIdleLoop);
            bw.Write(ExhaustIdleLoop);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(AirIntake);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Turbo);
            bw.Write(Unk19);
            bw.Write(Unk20);
            bw.Write(DumpValve);
            bw.Write(Unk22);
            bw.Write(Unk23);
            bw.Write(Transmission);
            bw.Write(Unk25);
            bw.Write(Unk26);
            bw.Write(Unk27);
            bw.Write(Ignition);
            bw.Write(ShutDown);
            bw.Write(EngineCoolingFan);
            bw.Write(ExhaustPops);
            bw.Write(DistantStart);
            bw.Write(Unk33);
            bw.Write(GearStickVolume);
            bw.Write(StartupMaster);
            bw.Write(EngineSubmix);
            bw.Write(EngineSubmixPreset);
            bw.Write(ExhaustSubmix);
            bw.Write(ExhaustSubmixPreset);//flags? separate?
            bw.Write(Unk40);
            bw.Write(Unk41);
            bw.Write(Unk42);
            bw.Write(GearShiftInteriorUpgraded);
            bw.Write(GearShiftExteriorUpgraded);//flags? separate?
            bw.Write(Unk45);
            bw.Write(Unk46);
            bw.Write(Unk47);
            bw.Write(Unk48);
            bw.Write(Unk49);
            bw.Write(Unk50);
            bw.Write(DumpValveUpgraded);//float?
            bw.Write(Unk52);
            bw.Write(TransmissionUpgraded);
            bw.Write(TurboUpgraded);
            bw.Write(AirIntakeUpgraded);
            bw.Write(ExhaustPopsUpgraded);

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "MasterVolume", MasterVolume.ToString());
            RelXml.ValueTag(sb, indent, "EngineLowVolume", EngineLowVolume.ToString());
            RelXml.ValueTag(sb, indent, "EngineHighVolume", EngineHighVolume.ToString());
            RelXml.ValueTag(sb, indent, "EngineNPCVolume", EngineNPCVolume.ToString());
            RelXml.StringTag(sb, indent, "EngineLow", RelXml.HashString(EngineLow));
            RelXml.StringTag(sb, indent, "EngineHigh", RelXml.HashString(EngineHigh));
            RelXml.StringTag(sb, indent, "ExhaustLow", RelXml.HashString(ExhaustLow));
            RelXml.StringTag(sb, indent, "ExhaustHigh", RelXml.HashString(ExhaustHigh));
            RelXml.StringTag(sb, indent, "RevsOff", RelXml.HashString(RevsOff));
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.StringTag(sb, indent, "EngineIdleLoop", RelXml.HashString(EngineIdleLoop));
            RelXml.StringTag(sb, indent, "ExhaustIdleLoop", RelXml.HashString(ExhaustIdleLoop));
            RelXml.ValueTag(sb, indent, "Unk13", Unk13.ToString());
            RelXml.ValueTag(sb, indent, "Unk14", Unk14.ToString());
            RelXml.StringTag(sb, indent, "AirIntake", RelXml.HashString(AirIntake));
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.ValueTag(sb, indent, "Unk17", Unk17.ToString());
            RelXml.StringTag(sb, indent, "Turbo", RelXml.HashString(Turbo));
            RelXml.ValueTag(sb, indent, "Unk19", Unk19.ToString());
            RelXml.ValueTag(sb, indent, "Unk20", Unk20.ToString());
            RelXml.StringTag(sb, indent, "DumpValve", RelXml.HashString(DumpValve));
            RelXml.ValueTag(sb, indent, "Unk22", Unk22.ToString());
            RelXml.ValueTag(sb, indent, "Unk23", Unk23.ToString());
            RelXml.StringTag(sb, indent, "Transmission", RelXml.HashString(Transmission));
            RelXml.ValueTag(sb, indent, "Unk25", Unk25.ToString());
            RelXml.ValueTag(sb, indent, "Unk26", Unk26.ToString());
            RelXml.ValueTag(sb, indent, "Unk27", Unk27.ToString());
            RelXml.StringTag(sb, indent, "Ignition", RelXml.HashString(Ignition));
            RelXml.StringTag(sb, indent, "ShutDown", RelXml.HashString(ShutDown));
            RelXml.StringTag(sb, indent, "EngineCoolingFan", RelXml.HashString(EngineCoolingFan));
            RelXml.StringTag(sb, indent, "ExhaustPops", RelXml.HashString(ExhaustPops));
            RelXml.StringTag(sb, indent, "DistantStart", RelXml.HashString(DistantStart));
            RelXml.ValueTag(sb, indent, "Unk33", Unk33.ToString());
            RelXml.ValueTag(sb, indent, "GearStickVolume", GearStickVolume.ToString());
            RelXml.StringTag(sb, indent, "StartupMaster", RelXml.HashString(StartupMaster));
            RelXml.StringTag(sb, indent, "EngineSubmix", RelXml.HashString(EngineSubmix));
            RelXml.StringTag(sb, indent, "EngineSubmixPreset", RelXml.HashString(EngineSubmixPreset));
            RelXml.StringTag(sb, indent, "ExhaustSubmix", RelXml.HashString(ExhaustSubmix));
            RelXml.StringTag(sb, indent, "ExhaustSubmixPreset", RelXml.HashString(ExhaustSubmixPreset));
            RelXml.StringTag(sb, indent, "Unk40", RelXml.HashString(Unk40));
            RelXml.StringTag(sb, indent, "Unk41", RelXml.HashString(Unk41));
            RelXml.ValueTag(sb, indent, "Unk42", Unk42.ToString());
            RelXml.StringTag(sb, indent, "GearShiftInteriorUpgraded", RelXml.HashString(GearShiftInteriorUpgraded));
            RelXml.StringTag(sb, indent, "GearShiftExteriorUpgraded", RelXml.HashString(GearShiftExteriorUpgraded));
            RelXml.ValueTag(sb, indent, "Unk45", Unk45.ToString());
            RelXml.ValueTag(sb, indent, "Unk46", Unk46.ToString());
            RelXml.ValueTag(sb, indent, "Unk47", Unk47.ToString());
            RelXml.ValueTag(sb, indent, "Unk48", Unk48.ToString());
            RelXml.ValueTag(sb, indent, "Unk49", Unk49.ToString());
            RelXml.ValueTag(sb, indent, "Unk50", Unk50.ToString());
            RelXml.StringTag(sb, indent, "DumpValveUpgraded", RelXml.HashString(DumpValveUpgraded));
            RelXml.ValueTag(sb, indent, "Unk52", Unk52.ToString());
            RelXml.StringTag(sb, indent, "TransmissionUpgraded", RelXml.HashString(TransmissionUpgraded));
            RelXml.StringTag(sb, indent, "TurboUpgraded", RelXml.HashString(TurboUpgraded));
            RelXml.StringTag(sb, indent, "AirIntakeUpgraded", RelXml.HashString(AirIntakeUpgraded));
            RelXml.StringTag(sb, indent, "ExhaustPopsUpgraded", RelXml.HashString(ExhaustPopsUpgraded));
        }
        public override void ReadXml(XmlNode node)
        {
            MasterVolume = Xml.GetChildIntAttribute(node, "MasterVolume", "value");
            EngineLowVolume = Xml.GetChildIntAttribute(node, "EngineLowVolume", "value");
            EngineHighVolume = Xml.GetChildIntAttribute(node, "EngineHighVolume", "value");
            EngineNPCVolume = Xml.GetChildIntAttribute(node, "EngineNPCVolume", "value");
            EngineLow = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineLow"));
            EngineHigh = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineHigh"));
            ExhaustLow = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustLow"));
            ExhaustHigh = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustHigh"));
            RevsOff = XmlRel.GetHash(Xml.GetChildInnerText(node, "RevsOff"));
            Unk09 = Xml.GetChildIntAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildIntAttribute(node, "Unk10", "value");
            EngineIdleLoop = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineIdleLoop"));
            ExhaustIdleLoop = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustIdleLoop"));
            Unk13 = Xml.GetChildIntAttribute(node, "Unk13", "value");
            Unk14 = Xml.GetChildIntAttribute(node, "Unk14", "value");
            AirIntake = XmlRel.GetHash(Xml.GetChildInnerText(node, "AirIntake"));
            Unk16 = Xml.GetChildIntAttribute(node, "Unk16", "value");
            Unk17 = Xml.GetChildIntAttribute(node, "Unk17", "value");
            Turbo = XmlRel.GetHash(Xml.GetChildInnerText(node, "Turbo"));
            Unk19 = Xml.GetChildIntAttribute(node, "Unk19", "value");
            Unk20 = Xml.GetChildIntAttribute(node, "Unk20", "value");
            DumpValve = XmlRel.GetHash(Xml.GetChildInnerText(node, "DumpValve"));
            Unk22 = Xml.GetChildIntAttribute(node, "Unk22", "value");
            Unk23 = Xml.GetChildIntAttribute(node, "Unk23", "value");
            Transmission = XmlRel.GetHash(Xml.GetChildInnerText(node, "Transmission"));
            Unk25 = Xml.GetChildIntAttribute(node, "Unk25", "value");
            Unk26 = Xml.GetChildIntAttribute(node, "Unk26", "value");
            Unk27 = Xml.GetChildIntAttribute(node, "Unk27", "value");
            Ignition = XmlRel.GetHash(Xml.GetChildInnerText(node, "Ignition"));
            ShutDown = XmlRel.GetHash(Xml.GetChildInnerText(node, "ShutDown"));
            EngineCoolingFan = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineCoolingFan"));
            ExhaustPops = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustPops"));
            DistantStart = XmlRel.GetHash(Xml.GetChildInnerText(node, "DistantStart"));
            Unk33 = Xml.GetChildIntAttribute(node, "Unk33", "value");
            GearStickVolume = Xml.GetChildIntAttribute(node, "GearStickVolume", "value");
            StartupMaster = XmlRel.GetHash(Xml.GetChildInnerText(node, "StartupMaster"));
            EngineSubmix = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineSubmix"));
            EngineSubmixPreset = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineSubmixPreset"));
            ExhaustSubmix = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustSubmix"));
            ExhaustSubmixPreset = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustSubmixPreset"));
            Unk40 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk40"));
            Unk41 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk41"));
            Unk42 = Xml.GetChildIntAttribute(node, "Unk42", "value");
            GearShiftInteriorUpgraded = XmlRel.GetHash(Xml.GetChildInnerText(node, "GearShiftInteriorUpgraded"));
            GearShiftExteriorUpgraded = XmlRel.GetHash(Xml.GetChildInnerText(node, "GearShiftExteriorUpgraded"));
            Unk45 = Xml.GetChildIntAttribute(node, "Unk45", "value");
            Unk46 = Xml.GetChildIntAttribute(node, "Unk46", "value");
            Unk47 = Xml.GetChildIntAttribute(node, "Unk47", "value");
            Unk48 = Xml.GetChildIntAttribute(node, "Unk48", "value");
            Unk49 = Xml.GetChildIntAttribute(node, "Unk49", "value");
            Unk50 = Xml.GetChildIntAttribute(node, "Unk50", "value");
            DumpValveUpgraded = XmlRel.GetHash(Xml.GetChildInnerText(node, "DumpValveUpgraded"));
            Unk52 = Xml.GetChildIntAttribute(node, "Unk52", "value");
            TransmissionUpgraded = XmlRel.GetHash(Xml.GetChildInnerText(node, "TransmissionUpgraded"));
            TurboUpgraded = XmlRel.GetHash(Xml.GetChildInnerText(node, "TurboUpgraded"));
            AirIntakeUpgraded = XmlRel.GetHash(Xml.GetChildInnerText(node, "AirIntakeUpgraded"));
            ExhaustPopsUpgraded = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustPopsUpgraded"));
        }
        public override MetaHash[] GetSynthHashes()
        {
            return new[] { EngineSubmix, EngineSubmixPreset, ExhaustSubmix, ExhaustSubmixPreset };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { EngineLow, EngineHigh, ExhaustLow, ExhaustHigh, RevsOff, EngineIdleLoop, ExhaustIdleLoop, AirIntake, Turbo, DumpValve, 
                Transmission, Ignition, ShutDown, EngineCoolingFan, ExhaustPops, DistantStart, StartupMaster, Unk40, Unk41,
                GearShiftInteriorUpgraded, GearShiftExteriorUpgraded, DumpValveUpgraded, TransmissionUpgraded,
                TurboUpgraded, AirIntakeUpgraded, ExhaustPopsUpgraded };
        }
    }
    [TC(typeof(EXP))] public class Dat151VehicleScannerParams : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public int ParamCount { get; set; }
        public Param[] Params;

        public class Param : IMetaXmlItem
        {
            public MetaHash Manufacturer { get; set; }
            public MetaHash Model { get; set; }
            public MetaHash Category { get; set; }
            public MetaHash ColorOverride { get; set; }

            public Param()
            { }
            public Param(BinaryReader br)
            {
                Manufacturer = br.ReadUInt32();
                Model = br.ReadUInt32();
                Category = br.ReadUInt32();
                ColorOverride = br.ReadUInt32();
            }
            public void Write(BinaryWriter bw)
            {
                bw.Write(Manufacturer);
                bw.Write(Model);
                bw.Write(Category);
                bw.Write(ColorOverride);
            }
            public void WriteXml(StringBuilder sb, int indent)
            {
                RelXml.StringTag(sb, indent, "Manufacturer", RelXml.HashString(Manufacturer));
                RelXml.StringTag(sb, indent, "Model", RelXml.HashString(Model));
                RelXml.StringTag(sb, indent, "Category", RelXml.HashString(Category));
                RelXml.StringTag(sb, indent, "ColorOverride", RelXml.HashString(ColorOverride));
            }
            public void ReadXml(XmlNode node)
            {
                Manufacturer = XmlRel.GetHash(Xml.GetChildInnerText(node, "Manufacturer"));
                Model = XmlRel.GetHash(Xml.GetChildInnerText(node, "Model"));
                Category = XmlRel.GetHash(Xml.GetChildInnerText(node, "Category"));
                ColorOverride = XmlRel.GetHash(Xml.GetChildInnerText(node, "ColorOverride"));
            }
        }

        public Dat151VehicleScannerParams(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.VehicleScannerParams;
            TypeID = (byte)Type;
        }
        public Dat151VehicleScannerParams(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            ParamCount = br.ReadInt32();
            Params = new Param[ParamCount];
            for (int i = 0; i < ParamCount; i++)
            {
                Params[i] = new Param(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(ParamCount);
            for (int i = 0; i < ParamCount; i++)
            {
                Params[i].Write(bw);
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.WriteItemArray(sb, Params, indent, "Params");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Params = XmlRel.ReadItemArray<Param>(node, "Params");
            ParamCount = (Params?.Length ?? 0);
        }
        public override MetaHash[] GetSoundHashes()
        {
            var list = new List<MetaHash>();
            foreach (var p in Params)
            {
                list.Add(p.Manufacturer);
                list.Add(p.Model);
                list.Add(p.Category);
                list.Add(p.ColorOverride);
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151Weapon : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public MetaHash PlayerFire { get; set; }
        public MetaHash SuppressedFire { get; set; }
        public MetaHash RapidFire { get; set; }
        public MetaHash Report { get; set; }
        public float Unk05 { get; set; }
        public int Unk06 { get; set; }
        public float Unk07 { get; set; }
        public MetaHash Echo { get; set; }
        public MetaHash Unk09 { get; set; }
        public MetaHash Unk10 { get; set; }
        public MetaHash Unk11 { get; set; }
        public MetaHash Unk12 { get; set; }
        public MetaHash Unk13 { get; set; }//eg 0xBB0A8AE1
        public MetaHash Unk14 { get; set; }
        public MetaHash Unk15 { get; set; }
        public MetaHash Unk16 { get; set; }
        public MetaHash Unk17 { get; set; }
        public MetaHash PickUpWeapon { get; set; }
        public int Unk19 { get; set; }//0,1,2
        public MetaHash Unk20 { get; set; }
        public MetaHash Unk21 { get; set; }
        public MetaHash Unk22 { get; set; }//eg fuel_can_soundset
        public MetaHash Unk23 { get; set; }
        public MetaHash InteriorFire { get; set; }
        public MetaHash Reload { get; set; }//soundset
        public MetaHash Unk26 { get; set; }
        public MetaHash Unk27 { get; set; }
        public int Unk28 { get; set; }//0,50
        public int Unk29 { get; set; }//0
        public MetaHash Aim { get; set; }
        public MetaHash Unk31 { get; set; }
        public MetaHash Unk32 { get; set; }
        public MetaHash SlowMotionFire { get; set; }
        public MetaHash Unk34 { get; set; }

        public MetaHash Unk35 { get; set; }
        public MetaHash Unk36 { get; set; }
        public MetaHash Unk37 { get; set; }
        public MetaHash SlowMotionReport { get; set; }
        public MetaHash Unk39 { get; set; }
        public MetaHash Unk40 { get; set; }
        public MetaHash Unk41 { get; set; }
        public MetaHash Unk42 { get; set; }
        public MetaHash Unk43 { get; set; }
        public MetaHash Unk44 { get; set; }
        public MetaHash Unk45 { get; set; }
        public MetaHash Unk46 { get; set; }//100, 30, null_sound ... both int (v3) and sound (v1)... TODO: fix this!
        public MetaHash Unk47 { get; set; }//20, null_sound ...      both int (v3) and sound (v1)...

        public int Unk48 { get; set; }
        public int Unk49 { get; set; }
        public int Unk50 { get; set; }

        public MetaHash Unk51 { get; set; }
        public MetaHash Unk52 { get; set; }
        public MetaHash Unk53 { get; set; }
        public MetaHash Unk54 { get; set; }
        public MetaHash Unk55 { get; set; }
        public MetaHash Unk56 { get; set; }
        public MetaHash Unk57 { get; set; }
        public MetaHash Unk58 { get; set; }
        public MetaHash Unk59 { get; set; }
        public MetaHash Unk60 { get; set; }
        public MetaHash Unk61 { get; set; }
        public MetaHash Unk62 { get; set; }
        public int Unk63 { get; set; }
        public int Unk64 { get; set; }
        public int Unk65 { get; set; }
        public int Unk66 { get; set; }
        public int Unk67 { get; set; }

        public int Version { get; set; }


        public Dat151Weapon(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Weapon;
            TypeID = (byte)Type;
        }
        public Dat151Weapon(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            PlayerFire = br.ReadUInt32();
            SuppressedFire = br.ReadUInt32();
            RapidFire = br.ReadUInt32();
            Report = br.ReadUInt32();
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadInt32();
            Unk07 = br.ReadSingle();
            Echo = br.ReadUInt32();
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadUInt32();
            Unk11 = br.ReadUInt32();
            Unk12 = br.ReadUInt32();
            Unk13 = br.ReadUInt32();//eg 0xBB0A8AE1
            Unk14 = br.ReadUInt32();
            Unk15 = br.ReadUInt32();
            Unk16 = br.ReadUInt32();
            Unk17 = br.ReadUInt32();
            PickUpWeapon = br.ReadUInt32();
            Unk19 = br.ReadInt32();//0,1,2
            Unk20 = br.ReadUInt32();
            Unk21 = br.ReadUInt32();
            Unk22 = br.ReadUInt32();
            Unk23 = br.ReadUInt32();
            InteriorFire = br.ReadUInt32();
            Reload = br.ReadUInt32();
            Unk26 = br.ReadUInt32();
            Unk27 = br.ReadUInt32();
            Unk28 = br.ReadInt32();//0,50
            Unk29 = br.ReadInt32();//0
            Aim = br.ReadUInt32();
            Unk31 = br.ReadUInt32();
            Unk32 = br.ReadUInt32();
            SlowMotionFire = br.ReadUInt32();
            Unk34 = br.ReadUInt32();

            Version = 0;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            switch (bytesleft)
            {
                case 0:
                    break;
                case 52:
                case 64:
                case 132:
                    Version = 1;
                    Unk35 = br.ReadUInt32();
                    Unk36 = br.ReadUInt32();
                    Unk37 = br.ReadUInt32();
                    SlowMotionReport = br.ReadUInt32();
                    Unk39 = br.ReadUInt32();
                    Unk40 = br.ReadUInt32();
                    Unk41 = br.ReadUInt32();
                    Unk42 = br.ReadUInt32();
                    Unk43 = br.ReadUInt32();
                    Unk44 = br.ReadUInt32();
                    Unk45 = br.ReadUInt32();
                    Unk46 = br.ReadUInt32();
                    Unk47 = br.ReadUInt32();

                    if (bytesleft >= 64)
                    {
                        Version = 2;
                        Unk48 = br.ReadInt32();
                        Unk49 = br.ReadInt32();
                        Unk50 = br.ReadInt32();

                        if (Unk48 != 0)
                        { }//only rarely hit!
                        if (Unk49 != 0)
                        { }//no hit
                        if (Unk50 != 0)
                        { }//no hit

                        if (bytesleft >= 132)
                        {
                            Version = 3;
                            Unk51 = br.ReadUInt32();
                            Unk52 = br.ReadUInt32();
                            Unk53 = br.ReadUInt32();
                            Unk54 = br.ReadUInt32();
                            Unk55 = br.ReadUInt32();
                            Unk56 = br.ReadUInt32();
                            Unk57 = br.ReadUInt32();
                            Unk58 = br.ReadUInt32();
                            Unk59 = br.ReadUInt32();
                            Unk60 = br.ReadUInt32();
                            Unk61 = br.ReadUInt32();
                            Unk62 = br.ReadUInt32();
                            Unk63 = br.ReadInt32();
                            Unk64 = br.ReadInt32();
                            Unk65 = br.ReadInt32();
                            Unk66 = br.ReadInt32();
                            Unk67 = br.ReadInt32();

                            if (bytesleft > 132)
                            { }//shouldn't get here
                        }
                    }
                    break;
                default:
                    break;
            }
            bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }

            if (Unk29 != 0)
            { }//no hit

        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(PlayerFire);
            bw.Write(SuppressedFire);
            bw.Write(RapidFire);
            bw.Write(Report);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Echo);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);//eg 0xBB0A8AE1
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(PickUpWeapon);
            bw.Write(Unk19);//0,1,2
            bw.Write(Unk20);
            bw.Write(Unk21);
            bw.Write(Unk22);
            bw.Write(Unk23);
            bw.Write(InteriorFire);
            bw.Write(Reload);
            bw.Write(Unk26);
            bw.Write(Unk27);
            bw.Write(Unk28);//0,50
            bw.Write(Unk29);//0
            bw.Write(Aim);
            bw.Write(Unk31);
            bw.Write(Unk32);
            bw.Write(SlowMotionFire);
            bw.Write(Unk34);

            if (Version >= 1)
            {
                bw.Write(Unk35);
                bw.Write(Unk36);
                bw.Write(Unk37);
                bw.Write(SlowMotionReport);
                bw.Write(Unk39);
                bw.Write(Unk40);
                bw.Write(Unk41);
                bw.Write(Unk42);
                bw.Write(Unk43);
                bw.Write(Unk44);
                bw.Write(Unk45);
                bw.Write(Unk46);
                bw.Write(Unk47);

                if (Version >= 2)
                {
                    bw.Write(Unk48);
                    bw.Write(Unk49);
                    bw.Write(Unk50);

                    if (Version >= 3)
                    {
                        bw.Write(Unk51);
                        bw.Write(Unk52);
                        bw.Write(Unk53);
                        bw.Write(Unk54);
                        bw.Write(Unk55);
                        bw.Write(Unk56);
                        bw.Write(Unk57);
                        bw.Write(Unk58);
                        bw.Write(Unk59);
                        bw.Write(Unk60);
                        bw.Write(Unk61);
                        bw.Write(Unk62);
                        bw.Write(Unk63);
                        bw.Write(Unk64);
                        bw.Write(Unk65);
                        bw.Write(Unk66);
                        bw.Write(Unk67);
                    }
                }
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Version", Version.ToString()); //CW invention, not an actual field!
            RelXml.StringTag(sb, indent, "PlayerFire", RelXml.HashString(PlayerFire));
            RelXml.StringTag(sb, indent, "SuppressedFire", RelXml.HashString(SuppressedFire));
            RelXml.StringTag(sb, indent, "RapidFire", RelXml.HashString(RapidFire));
            RelXml.StringTag(sb, indent, "Report", RelXml.HashString(Report));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", Unk06.ToString());
            RelXml.ValueTag(sb, indent, "Unk07", FloatUtil.ToString(Unk07));
            RelXml.StringTag(sb, indent, "Echo", RelXml.HashString(Echo));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
            RelXml.StringTag(sb, indent, "Unk11", RelXml.HashString(Unk11));
            RelXml.StringTag(sb, indent, "Unk12", RelXml.HashString(Unk12));
            RelXml.StringTag(sb, indent, "Unk13", RelXml.HashString(Unk13));
            RelXml.StringTag(sb, indent, "Unk14", RelXml.HashString(Unk14));
            RelXml.StringTag(sb, indent, "Unk15", RelXml.HashString(Unk15));
            RelXml.StringTag(sb, indent, "Unk16", RelXml.HashString(Unk16));
            RelXml.StringTag(sb, indent, "Unk17", RelXml.HashString(Unk17));
            RelXml.StringTag(sb, indent, "PickUpWeapon", RelXml.HashString(PickUpWeapon));
            RelXml.ValueTag(sb, indent, "Unk19", Unk19.ToString());
            RelXml.StringTag(sb, indent, "Unk20", RelXml.HashString(Unk20));
            RelXml.StringTag(sb, indent, "Unk21", RelXml.HashString(Unk21));
            RelXml.StringTag(sb, indent, "Unk22", RelXml.HashString(Unk22));
            RelXml.StringTag(sb, indent, "Unk23", RelXml.HashString(Unk23));
            RelXml.StringTag(sb, indent, "InteriorFire", RelXml.HashString(InteriorFire));
            RelXml.StringTag(sb, indent, "Reload", RelXml.HashString(Reload));
            RelXml.StringTag(sb, indent, "Unk26", RelXml.HashString(Unk26));
            RelXml.StringTag(sb, indent, "Unk27", RelXml.HashString(Unk27));
            RelXml.ValueTag(sb, indent, "Unk28", Unk28.ToString());
            RelXml.ValueTag(sb, indent, "Unk29", Unk29.ToString());
            RelXml.StringTag(sb, indent, "Aim", RelXml.HashString(Aim));
            RelXml.StringTag(sb, indent, "Unk31", RelXml.HashString(Unk31));
            RelXml.StringTag(sb, indent, "Unk32", RelXml.HashString(Unk32));
            RelXml.StringTag(sb, indent, "SlowMotionFire", RelXml.HashString(SlowMotionFire));
            RelXml.StringTag(sb, indent, "Unk34", RelXml.HashString(Unk34));

            if (Version >= 1)
            {
                RelXml.StringTag(sb, indent, "Unk35", RelXml.HashString(Unk35));
                RelXml.StringTag(sb, indent, "Unk36", RelXml.HashString(Unk36));
                RelXml.StringTag(sb, indent, "Unk37", RelXml.HashString(Unk37));
                RelXml.StringTag(sb, indent, "SlowMotionReport", RelXml.HashString(SlowMotionReport));
                RelXml.StringTag(sb, indent, "Unk39", RelXml.HashString(Unk39));
                RelXml.StringTag(sb, indent, "Unk40", RelXml.HashString(Unk40));
                RelXml.StringTag(sb, indent, "Unk41", RelXml.HashString(Unk41));
                RelXml.StringTag(sb, indent, "Unk42", RelXml.HashString(Unk42));
                RelXml.StringTag(sb, indent, "Unk43", RelXml.HashString(Unk43));
                RelXml.StringTag(sb, indent, "Unk44", RelXml.HashString(Unk44));
                RelXml.StringTag(sb, indent, "Unk45", RelXml.HashString(Unk45));
                RelXml.StringTag(sb, indent, "Unk46", RelXml.HashString(Unk46));
                RelXml.StringTag(sb, indent, "Unk47", RelXml.HashString(Unk47));

                if (Version >= 2)
                {
                    RelXml.ValueTag(sb, indent, "Unk48", Unk48.ToString());
                    RelXml.ValueTag(sb, indent, "Unk49", Unk49.ToString());
                    RelXml.ValueTag(sb, indent, "Unk50", Unk50.ToString());

                    if (Version >= 3)
                    {
                        RelXml.StringTag(sb, indent, "Unk51", RelXml.HashString(Unk51));
                        RelXml.StringTag(sb, indent, "Unk52", RelXml.HashString(Unk52));
                        RelXml.StringTag(sb, indent, "Unk53", RelXml.HashString(Unk53));
                        RelXml.StringTag(sb, indent, "Unk54", RelXml.HashString(Unk54));
                        RelXml.StringTag(sb, indent, "Unk55", RelXml.HashString(Unk55));
                        RelXml.StringTag(sb, indent, "Unk56", RelXml.HashString(Unk56));
                        RelXml.StringTag(sb, indent, "Unk57", RelXml.HashString(Unk57));
                        RelXml.StringTag(sb, indent, "Unk58", RelXml.HashString(Unk58));
                        RelXml.StringTag(sb, indent, "Unk59", RelXml.HashString(Unk59));
                        RelXml.StringTag(sb, indent, "Unk60", RelXml.HashString(Unk60));
                        RelXml.StringTag(sb, indent, "Unk61", RelXml.HashString(Unk61));
                        RelXml.StringTag(sb, indent, "Unk62", RelXml.HashString(Unk62));
                        RelXml.ValueTag(sb, indent, "Unk63", Unk63.ToString());
                        RelXml.ValueTag(sb, indent, "Unk64", Unk64.ToString());
                        RelXml.ValueTag(sb, indent, "Unk65", Unk65.ToString());
                        RelXml.ValueTag(sb, indent, "Unk66", Unk66.ToString());
                        RelXml.ValueTag(sb, indent, "Unk67", Unk67.ToString());
                    }
                }
            }
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Version = Xml.GetChildIntAttribute(node, "Version", "value");
            PlayerFire = XmlRel.GetHash(Xml.GetChildInnerText(node, "PlayerFire"));
            SuppressedFire = XmlRel.GetHash(Xml.GetChildInnerText(node, "SuppressedFire"));
            RapidFire = XmlRel.GetHash(Xml.GetChildInnerText(node, "RapidFire"));
            Report = XmlRel.GetHash(Xml.GetChildInnerText(node, "Report"));
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildIntAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildFloatAttribute(node, "Unk07", "value");
            Echo = XmlRel.GetHash(Xml.GetChildInnerText(node, "Echo"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
            Unk11 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk11"));
            Unk12 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk12"));
            Unk13 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk13"));
            Unk14 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk14"));
            Unk15 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk15"));
            Unk16 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk16"));
            Unk17 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk17"));
            PickUpWeapon = XmlRel.GetHash(Xml.GetChildInnerText(node, "PickUpWeapon"));
            Unk19 = Xml.GetChildIntAttribute(node, "Unk19", "value");
            Unk20 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk20"));
            Unk21 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk21"));
            Unk22 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk22"));
            Unk23 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk23"));
            InteriorFire = XmlRel.GetHash(Xml.GetChildInnerText(node, "InteriorFire"));
            Reload = XmlRel.GetHash(Xml.GetChildInnerText(node, "Reload"));
            Unk26 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk26"));
            Unk27 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk27"));
            Unk28 = Xml.GetChildIntAttribute(node, "Unk28", "value");
            Unk29 = Xml.GetChildIntAttribute(node, "Unk29", "value");
            Aim = XmlRel.GetHash(Xml.GetChildInnerText(node, "Aim"));
            Unk31 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk31"));
            Unk32 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk32"));
            SlowMotionFire = XmlRel.GetHash(Xml.GetChildInnerText(node, "SlowMotionFire"));
            Unk34 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk34"));

            if (Version >= 1)
            {
                Unk35 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk35"));
                Unk36 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk36"));
                Unk37 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk37"));
                SlowMotionReport = XmlRel.GetHash(Xml.GetChildInnerText(node, "SlowMotionReport"));
                Unk39 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk39"));
                Unk40 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk40"));
                Unk41 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk41"));
                Unk42 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk42"));
                Unk43 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk43"));
                Unk44 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk44"));
                Unk45 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk45"));
                Unk46 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk46"));
                Unk47 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk47"));

                if (Version >= 2)
                {
                    Unk48 = Xml.GetChildIntAttribute(node, "Unk48", "value");
                    Unk49 = Xml.GetChildIntAttribute(node, "Unk49", "value");
                    Unk50 = Xml.GetChildIntAttribute(node, "Unk50", "value");

                    if (Version >= 3)
                    {
                        Unk51 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk51"));
                        Unk52 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk52"));
                        Unk53 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk53"));
                        Unk54 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk54"));
                        Unk55 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk55"));
                        Unk56 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk56"));
                        Unk57 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk57"));
                        Unk58 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk58"));
                        Unk59 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk59"));
                        Unk60 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk60"));
                        Unk61 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk61"));
                        Unk62 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk62"));
                        Unk63 = Xml.GetChildIntAttribute(node, "Unk63", "value");
                        Unk64 = Xml.GetChildIntAttribute(node, "Unk64", "value");
                        Unk65 = Xml.GetChildIntAttribute(node, "Unk65", "value");
                        Unk66 = Xml.GetChildIntAttribute(node, "Unk66", "value");
                        Unk67 = Xml.GetChildIntAttribute(node, "Unk67", "value");
                    }
                }
            }
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { PlayerFire, SuppressedFire, RapidFire, Report, Echo, Unk09, Unk10, Unk11, Unk12, Unk13, Unk14, Unk15, Unk16, Unk17, PickUpWeapon,
                Unk20, Unk21, Unk22, Unk23, InteriorFire, Reload, Unk26, Unk27, Aim, Unk31, Unk32, SlowMotionFire, Unk34, Unk35, Unk36, Unk37, SlowMotionReport,
                Unk39, Unk40, Unk41, Unk42, Unk43, Unk44, Unk45, Unk46, Unk47, Unk51, Unk52, Unk53, Unk54, Unk55, Unk56, Unk57, Unk58, Unk59, Unk60, Unk61, Unk62 };
        }
    }
    [TC(typeof(EXP))] public class Dat151Explosion : Dat151RelData
    {
        public FlagsUint Unk01 { get; set; }
        public MetaHash Main { get; set; }
        public MetaHash Debris { get; set; }
        public float Unk04 { get; set; }
        public float Unk05 { get; set; }
        public float Unk06 { get; set; }
        public float Unk07 { get; set; }
        public float Unk08 { get; set; }
        public MetaHash SlowMotion { get; set; }
        public MetaHash Unk10 { get; set; }
        public int Unk11 { get; set; }
        public int Unk12 { get; set; }

        public Dat151Explosion(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Explosion;
            TypeID = (byte)Type;
        }
        public Dat151Explosion(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();//flags
            Main = br.ReadUInt32();//hash
            Debris = br.ReadUInt32();//hash
            Unk04 = br.ReadSingle();//float
            Unk05 = br.ReadSingle();//float
            Unk06 = br.ReadSingle();//float
            Unk07 = br.ReadSingle();//float
            Unk08 = br.ReadSingle();//float
            SlowMotion = br.ReadUInt32();//hash
            Unk10 = br.ReadUInt32();//hash
            Unk11 = br.ReadInt32();//0
            Unk12 = br.ReadInt32();//0

            if (Unk11 != 0)
            { }
            if (Unk12 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);//flags
            bw.Write(Main);//hash
            bw.Write(Debris);//hash
            bw.Write(Unk04);//float
            bw.Write(Unk05);//float
            bw.Write(Unk06);//float
            bw.Write(Unk07);//float
            bw.Write(Unk08);//float
            bw.Write(SlowMotion);//hash
            bw.Write(Unk10);//hash
            bw.Write(Unk11);//0
            bw.Write(Unk12);//0
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", "0x" + Unk01.Hex);
            RelXml.StringTag(sb, indent, "Main", RelXml.HashString(Main));
            RelXml.StringTag(sb, indent, "Debris", RelXml.HashString(Debris));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", FloatUtil.ToString(Unk07));
            RelXml.ValueTag(sb, indent, "Unk08", FloatUtil.ToString(Unk08));
            RelXml.StringTag(sb, indent, "SlowMotion", RelXml.HashString(SlowMotion));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
            RelXml.ValueTag(sb, indent, "Unk11", Unk11.ToString());
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildUIntAttribute(node, "Unk01", "value");
            Main = XmlRel.GetHash(Xml.GetChildInnerText(node, "Main"));
            Debris = XmlRel.GetHash(Xml.GetChildInnerText(node, "Debris"));
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildFloatAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildFloatAttribute(node, "Unk08", "value");
            SlowMotion = XmlRel.GetHash(Xml.GetChildInnerText(node, "SlowMotion"));
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
            Unk11 = Xml.GetChildIntAttribute(node, "Unk11", "value");
            Unk12 = Xml.GetChildIntAttribute(node, "Unk12", "value");
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Main, Debris, SlowMotion, Unk10 };
        }
    }
    [TC(typeof(EXP))] public class Dat151PedVoiceGroupItem : IMetaXmlItem
    {
        public MetaHash Name { get; set; }
        public FlagsUint Unk1 { get; set; }
        public FlagsUint Unk2 { get; set; }

        public Dat151PedVoiceGroupItem()
        { }
        public Dat151PedVoiceGroupItem(BinaryReader br)
        {
            Name = br.ReadUInt32();
            Unk1 = br.ReadUInt32();
            Unk2 = br.ReadUInt32();

            if (Unk1 != 0)
            { }//no hit
            if (Unk2 != 0)
            { }//no hit
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Name);
            bw.Write(Unk1);
            bw.Write(Unk2);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Name", RelXml.HashString(Name));
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.Value.ToString());
            RelXml.ValueTag(sb, indent, "Unk2", Unk2.Value.ToString());
        }
        public void ReadXml(XmlNode node)
        {
            Name = XmlRel.GetHash(Xml.GetChildInnerText(node, "Name"));
            Unk1 = Xml.GetChildUIntAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildUIntAttribute(node, "Unk2", "value");
        }
        public override string ToString()
        {
            return Name.ToString() + ", " + Unk1.Value.ToString() + ", " + Unk2.Value.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat151PedVoiceGroup : Dat151RelData
    {
        public FlagsUint Unk00 { get; set; }//flags?
        public byte Unk01 { get; set; } = 94;
        public byte Unk02 { get; set; } = 57;
        public byte Unk03 { get; set; } = 245;
        public byte FullCount { get; set; }
        public Dat151PedVoiceGroupItem[] Full { get; set; }
        public byte MiniCount { get; set; }
        public Dat151PedVoiceGroupItem[] Mini { get; set; }
        public byte UnkItemsCount { get; set; }
        public Dat151PedVoiceGroupItem[] UnkItems { get; set; }
        public byte Unk07 { get; set; } //item count4? (=0)



        public Dat151PedVoiceGroup(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.PedVoiceGroup;
            TypeID = (byte)Type;
        }
        public Dat151PedVoiceGroup(RelData d, BinaryReader br) : base(d, br)
        {
            Unk00 = br.ReadUInt32();//flags?
            Unk01 = br.ReadByte();//94
            Unk02 = br.ReadByte();//57
            Unk03 = br.ReadByte();//245

            FullCount = br.ReadByte();
            Full = new Dat151PedVoiceGroupItem[FullCount];
            for (int i = 0; i < FullCount; i++)
            {
                Full[i] = new Dat151PedVoiceGroupItem(br);
            }

            MiniCount = br.ReadByte();
            Mini = new Dat151PedVoiceGroupItem[MiniCount];
            for (int i = 0; i < MiniCount; i++)
            {
                Mini[i] = new Dat151PedVoiceGroupItem(br);
            }

            UnkItemsCount = br.ReadByte();
            UnkItems = new Dat151PedVoiceGroupItem[UnkItemsCount];
            for (int i = 0; i < UnkItemsCount; i++)
            {
                UnkItems[i] = new Dat151PedVoiceGroupItem(br);
            }

            Unk07 = br.ReadByte();
            //Items4 = new UnkStruct[Unk07];
            //for (int i = 0; i < Unk07; i++)
            //{
            //    Items4[i] = new UnkStruct(br);
            //}



            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
            //if (Unk06 != 0)
            //{ }
            //if (Unk04 != 0)
            //{ }

        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk00);//flags?
            bw.Write(Unk01);//94
            bw.Write(Unk02);//57
            bw.Write(Unk03);//245
            bw.Write(FullCount);
            for (int i = 0; i < FullCount; i++)
            {
                Full[i].Write(bw);
            }
            bw.Write(MiniCount);
            for (int i = 0; i < MiniCount; i++)
            {
                Mini[i].Write(bw);
            }
            bw.Write(UnkItemsCount);
            for (int i = 0; i < UnkItemsCount; i++)
            {
                UnkItems[i].Write(bw);
            }
            bw.Write(Unk07);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk00", "0x" + Unk00.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.WriteItemArray(sb, Full, indent, "Full");
            RelXml.WriteItemArray(sb, Mini, indent, "Mini");
            RelXml.WriteItemArray(sb, UnkItems, indent, "UnkItems");
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk00 = Xml.GetChildUIntAttribute(node, "Unk00", "value");
            Unk01 = (byte)Xml.GetChildUIntAttribute(node, "Unk01", "value");
            Unk02 = (byte)Xml.GetChildUIntAttribute(node, "Unk02", "value");
            Unk03 = (byte)Xml.GetChildUIntAttribute(node, "Unk03", "value");
            Full = XmlRel.ReadItemArray<Dat151PedVoiceGroupItem>(node, "Full");
            FullCount = (byte)(Full?.Length ?? 0);
            Mini = XmlRel.ReadItemArray<Dat151PedVoiceGroupItem>(node, "Mini");
            MiniCount = (byte)(Mini?.Length ?? 0);
            UnkItems = XmlRel.ReadItemArray<Dat151PedVoiceGroupItem>(node, "UnkItems");
            UnkItemsCount = (byte)(UnkItems?.Length ?? 0);
            Unk07 = (byte)Xml.GetChildUIntAttribute(node, "Unk07", "value");
        }
        public override MetaHash[] GetSpeechHashes()
        {
            var list = new List<MetaHash>();
            if (Full != null)
            {
                foreach (var item in Full)
                {
                    list.Add(item.Name);
                }
            }
            if (Mini != null)
            {
                foreach (var item in Mini)
                {
                    list.Add(item.Name);
                }
            }
            if (UnkItems != null)
            {
                foreach (var item in UnkItems)
                {
                    list.Add(item.Name);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151EntityEmitter : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public MetaHash Unk01 { get; set; }
        public float Unk02 { get; set; }
        public float Unk03 { get; set; }
        public float Unk04 { get; set; }
        public float Unk05 { get; set; }
        public float Unk06 { get; set; }
        public float Unk07 { get; set; }
        public float Unk08 { get; set; }
        public MetaHash Unk09 { get; set; }//always 0
        public int Unk10 { get; set; }
        public float Unk11 { get; set; }

        public Dat151EntityEmitter(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.EntityEmitter;
            TypeID = (byte)Type;
        }
        public Dat151EntityEmitter(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadSingle();
            Unk07 = br.ReadSingle();
            Unk08 = br.ReadSingle();
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadInt32();
            Unk11 = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", FloatUtil.ToString(Unk07));
            RelXml.ValueTag(sb, indent, "Unk08", FloatUtil.ToString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.ValueTag(sb, indent, "Unk11", FloatUtil.ToString(Unk11));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildFloatAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildFloatAttribute(node, "Unk08", "value");
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = Xml.GetChildIntAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildFloatAttribute(node, "Unk11", "value");
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk01 };
        }
    }
    [TC(typeof(EXP))] public class Dat151Boat : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public MetaHash Engine { get; set; }
        public MetaHash EngineVolume { get; set; }
        public MetaHash EnginePitch { get; set; }
        public MetaHash Engine2 { get; set; }
        public MetaHash Engine2Volume { get; set; }
        public MetaHash Engine2Pitch { get; set; }
        public MetaHash EngineLowReso { get; set; }
        public MetaHash EngineLowResoVolume { get; set; }
        public MetaHash EngineLowResoPitch { get; set; }
        public MetaHash EngineIdleLoop { get; set; }
        public MetaHash EngineIdleVolume { get; set; }
        public MetaHash EngineIdlePitch { get; set; }
        public MetaHash WaterTurbulence { get; set; }
        public MetaHash WaterTurbulenceVolume { get; set; }
        public MetaHash Unk15 { get; set; }//doesn't seem to match anything? always 0x6B3DC4A2
        public MetaHash Unk16 { get; set; }
        public MetaHash Unk17 { get; set; }
        public MetaHash Unk18 { get; set; }
        public MetaHash PoliceScannerParams { get; set; }//scanner params
        public int Unk20 { get; set; }
        public MetaHash Horn { get; set; }
        public MetaHash Ignition { get; set; }
        public MetaHash Shutdown { get; set; }
        public MetaHash Unk24 { get; set; }//0
        public MetaHash EngineSubmix { get; set; }//engine submix
        public MetaHash EngineSubmixPreset { get; set; }//engine submix preset
        public MetaHash ExhaustSubmix { get; set; }//exhaust submix
        public MetaHash ExhaustSubmixPreset { get; set; }//exhaust submix preset
        public MetaHash Collision { get; set; }
        public MetaHash Unk30 { get; set; }//engine environment
        public MetaHash Unk31 { get; set; }//exhaust environment?
        public MetaHash WaveHitMedium { get; set; }//wave hit (medium?)
        public MetaHash Unk33 { get; set; }//0
        public MetaHash IdleHullSlap { get; set; }
        public MetaHash Unk35 { get; set; }//curve
        public MetaHash EngineGranular { get; set; }//granular engine
        public MetaHash BankSpray { get; set; }
        public MetaHash Ignition2 { get; set; }
        public MetaHash Startup { get; set; }//startup
        public MetaHash Unk40 { get; set; }//curve
        public MetaHash SubTurn { get; set; }
        public MetaHash Unk42 { get; set; }//constant_one (curve)
        public MetaHash Unk43 { get; set; }//curve
        public MetaHash Unk44 { get; set; }//curve
        public MetaHash SandSkid { get; set; }
        public float Unk46 { get; set; }
        public float Unk47 { get; set; }
        public float Unk48 { get; set; }
        public MetaHash Unk49 { get; set; }
        public MetaHash Hull { get; set; }
        public MetaHash Unk51 { get; set; }
        public MetaHash Fire { get; set; }
        public MetaHash DoorOpen { get; set; }
        public MetaHash DoorClose { get; set; }
        public MetaHash Unk55 { get; set; }
        public MetaHash Unk56 { get; set; }
        public MetaHash Unk57 { get; set; }
        public MetaHash Unk58 { get; set; }
        public MetaHash SubCreaks { get; set; }
        public MetaHash WaveHitBigAir { get; set; }//wave hit (big air?)
        public float Unk61 { get; set; }
        public MetaHash Unk62 { get; set; }
        public MetaHash Unk63 { get; set; }


        public Dat151Boat(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Boat;
            TypeID = (byte)Type;
        }
        public Dat151Boat(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Engine = br.ReadUInt32();
            EngineVolume = br.ReadUInt32();
            EnginePitch = br.ReadUInt32();
            Engine2 = br.ReadUInt32();
            Engine2Volume = br.ReadUInt32();
            Engine2Pitch = br.ReadUInt32();
            EngineLowReso = br.ReadUInt32();
            EngineLowResoVolume = br.ReadUInt32();
            EngineLowResoPitch = br.ReadUInt32();
            EngineIdleLoop = br.ReadUInt32();
            EngineIdleVolume = br.ReadUInt32();
            EngineIdlePitch = br.ReadUInt32();
            WaterTurbulence = br.ReadUInt32();
            WaterTurbulenceVolume = br.ReadUInt32();
            Unk15 = br.ReadUInt32();
            Unk16 = br.ReadUInt32();
            Unk17 = br.ReadUInt32();
            Unk18 = br.ReadUInt32();
            PoliceScannerParams = br.ReadUInt32();
            Unk20 = br.ReadInt32();
            Horn = br.ReadUInt32();
            Ignition = br.ReadUInt32();
            Shutdown = br.ReadUInt32();
            Unk24 = br.ReadUInt32();
            EngineSubmix = br.ReadUInt32();
            EngineSubmixPreset = br.ReadUInt32();
            ExhaustSubmix = br.ReadUInt32();
            ExhaustSubmixPreset = br.ReadUInt32();
            Collision = br.ReadUInt32();
            Unk30 = br.ReadUInt32();
            Unk31 = br.ReadUInt32();
            WaveHitMedium = br.ReadUInt32();
            Unk33 = br.ReadUInt32();
            IdleHullSlap = br.ReadUInt32();
            Unk35 = br.ReadUInt32();
            EngineGranular = br.ReadUInt32();
            BankSpray = br.ReadUInt32();
            Ignition2 = br.ReadUInt32();
            Startup = br.ReadUInt32();
            Unk40 = br.ReadUInt32();
            SubTurn = br.ReadUInt32();
            Unk42 = br.ReadUInt32();
            Unk43 = br.ReadUInt32();
            Unk44 = br.ReadUInt32();
            SandSkid = br.ReadUInt32();
            Unk46 = br.ReadSingle();
            Unk47 = br.ReadSingle();
            Unk48 = br.ReadSingle();
            Unk49 = br.ReadUInt32();
            Hull = br.ReadUInt32();
            Unk51 = br.ReadUInt32();
            Fire = br.ReadUInt32();
            DoorOpen = br.ReadUInt32();
            DoorClose = br.ReadUInt32();
            Unk55 = br.ReadUInt32();
            Unk56 = br.ReadUInt32();
            Unk57 = br.ReadUInt32();
            Unk58 = br.ReadUInt32();
            SubCreaks = br.ReadUInt32();
            WaveHitBigAir = br.ReadUInt32();
            Unk61 = br.ReadSingle();
            Unk62 = br.ReadUInt32();
            Unk63 = br.ReadUInt32();

            if (Unk15 != 0x6B3DC4A2)
            { }//no hit
            if (Unk24 != 0)
            { }//no hit
            if (Unk33 != 0)
            { }//no hit

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Engine);
            bw.Write(EngineVolume);
            bw.Write(EnginePitch);
            bw.Write(Engine2);
            bw.Write(Engine2Volume);
            bw.Write(Engine2Pitch);
            bw.Write(EngineLowReso);
            bw.Write(EngineLowResoVolume);
            bw.Write(EngineLowResoPitch);
            bw.Write(EngineIdleLoop);
            bw.Write(EngineIdleVolume);
            bw.Write(EngineIdlePitch);
            bw.Write(WaterTurbulence);
            bw.Write(WaterTurbulenceVolume);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
            bw.Write(PoliceScannerParams);
            bw.Write(Unk20);
            bw.Write(Horn);
            bw.Write(Ignition);
            bw.Write(Shutdown);
            bw.Write(Unk24);
            bw.Write(EngineSubmix);
            bw.Write(EngineSubmixPreset);
            bw.Write(ExhaustSubmix);
            bw.Write(ExhaustSubmixPreset);
            bw.Write(Collision);
            bw.Write(Unk30);
            bw.Write(Unk31);
            bw.Write(WaveHitMedium);
            bw.Write(Unk33);
            bw.Write(IdleHullSlap);
            bw.Write(Unk35);
            bw.Write(EngineGranular);
            bw.Write(BankSpray);
            bw.Write(Ignition2);
            bw.Write(Startup);
            bw.Write(Unk40);
            bw.Write(SubTurn);
            bw.Write(Unk42);
            bw.Write(Unk43);
            bw.Write(Unk44);
            bw.Write(SandSkid);
            bw.Write(Unk46);
            bw.Write(Unk47);
            bw.Write(Unk48);
            bw.Write(Unk49);
            bw.Write(Hull);
            bw.Write(Unk51);
            bw.Write(Fire);
            bw.Write(DoorOpen);
            bw.Write(DoorClose);
            bw.Write(Unk55);
            bw.Write(Unk56);
            bw.Write(Unk57);
            bw.Write(Unk58);
            bw.Write(SubCreaks);
            bw.Write(WaveHitBigAir);
            bw.Write(Unk61);
            bw.Write(Unk62);
            bw.Write(Unk63);

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.StringTag(sb, indent, "Engine", RelXml.HashString(Engine));
            RelXml.StringTag(sb, indent, "EngineVolume", RelXml.HashString(EngineVolume));
            RelXml.StringTag(sb, indent, "EnginePitch", RelXml.HashString(EnginePitch));
            RelXml.StringTag(sb, indent, "Engine2", RelXml.HashString(Engine2));
            RelXml.StringTag(sb, indent, "Engine2Volume", RelXml.HashString(Engine2Volume));
            RelXml.StringTag(sb, indent, "Engine2Pitch", RelXml.HashString(Engine2Pitch));
            RelXml.StringTag(sb, indent, "EngineLowReso", RelXml.HashString(EngineLowReso));
            RelXml.StringTag(sb, indent, "EngineLowResoVolume", RelXml.HashString(EngineLowResoVolume));
            RelXml.StringTag(sb, indent, "EngineLowResoPitch", RelXml.HashString(EngineLowResoPitch));
            RelXml.StringTag(sb, indent, "EngineIdleLoop", RelXml.HashString(EngineIdleLoop));
            RelXml.StringTag(sb, indent, "EngineIdleVolume", RelXml.HashString(EngineIdleVolume));
            RelXml.StringTag(sb, indent, "EngineIdlePitch", RelXml.HashString(EngineIdlePitch));
            RelXml.StringTag(sb, indent, "WaterTurbulence", RelXml.HashString(WaterTurbulence));
            RelXml.StringTag(sb, indent, "WaterTurbulenceVolume", RelXml.HashString(WaterTurbulenceVolume));
            RelXml.StringTag(sb, indent, "Unk15", RelXml.HashString(Unk15));
            RelXml.StringTag(sb, indent, "Unk16", RelXml.HashString(Unk16));
            RelXml.StringTag(sb, indent, "Unk17", RelXml.HashString(Unk17));
            RelXml.StringTag(sb, indent, "Unk18", RelXml.HashString(Unk18));
            RelXml.StringTag(sb, indent, "PoliceScannerParams", RelXml.HashString(PoliceScannerParams));
            RelXml.ValueTag(sb, indent, "Unk20", Unk20.ToString());
            RelXml.StringTag(sb, indent, "Horn", RelXml.HashString(Horn));
            RelXml.StringTag(sb, indent, "Ignition", RelXml.HashString(Ignition));
            RelXml.StringTag(sb, indent, "Shutdown", RelXml.HashString(Shutdown));
            RelXml.StringTag(sb, indent, "Unk24", RelXml.HashString(Unk24));
            RelXml.StringTag(sb, indent, "EngineSubmix", RelXml.HashString(EngineSubmix));
            RelXml.StringTag(sb, indent, "EngineSubmixPreset", RelXml.HashString(EngineSubmixPreset));
            RelXml.StringTag(sb, indent, "ExhaustSubmix", RelXml.HashString(ExhaustSubmix));
            RelXml.StringTag(sb, indent, "ExhaustSubmixPreset", RelXml.HashString(ExhaustSubmixPreset));
            RelXml.StringTag(sb, indent, "Collision", RelXml.HashString(Collision));
            RelXml.StringTag(sb, indent, "Unk30", RelXml.HashString(Unk30));
            RelXml.StringTag(sb, indent, "Unk31", RelXml.HashString(Unk31));
            RelXml.StringTag(sb, indent, "WaveHitMedium", RelXml.HashString(WaveHitMedium));
            RelXml.StringTag(sb, indent, "Unk33", RelXml.HashString(Unk33));
            RelXml.StringTag(sb, indent, "IdleHullSlap", RelXml.HashString(IdleHullSlap));
            RelXml.StringTag(sb, indent, "Unk35", RelXml.HashString(Unk35));
            RelXml.StringTag(sb, indent, "EngineGranular", RelXml.HashString(EngineGranular));
            RelXml.StringTag(sb, indent, "BankSpray", RelXml.HashString(BankSpray));
            RelXml.StringTag(sb, indent, "Ignition2", RelXml.HashString(Ignition2));
            RelXml.StringTag(sb, indent, "Startup", RelXml.HashString(Startup));
            RelXml.StringTag(sb, indent, "Unk40", RelXml.HashString(Unk40));
            RelXml.StringTag(sb, indent, "SubTurn", RelXml.HashString(SubTurn));
            RelXml.StringTag(sb, indent, "Unk42", RelXml.HashString(Unk42));
            RelXml.StringTag(sb, indent, "Unk43", RelXml.HashString(Unk43));
            RelXml.StringTag(sb, indent, "Unk44", RelXml.HashString(Unk44));
            RelXml.StringTag(sb, indent, "SandSkid", RelXml.HashString(SandSkid));
            RelXml.ValueTag(sb, indent, "Unk46", FloatUtil.ToString(Unk46));
            RelXml.ValueTag(sb, indent, "Unk47", FloatUtil.ToString(Unk47));
            RelXml.ValueTag(sb, indent, "Unk48", FloatUtil.ToString(Unk48));
            RelXml.StringTag(sb, indent, "Unk49", RelXml.HashString(Unk49));
            RelXml.StringTag(sb, indent, "Hull", RelXml.HashString(Hull));
            RelXml.StringTag(sb, indent, "Unk51", RelXml.HashString(Unk51));
            RelXml.StringTag(sb, indent, "Fire", RelXml.HashString(Fire));
            RelXml.StringTag(sb, indent, "DoorOpen", RelXml.HashString(DoorOpen));
            RelXml.StringTag(sb, indent, "DoorClose", RelXml.HashString(DoorClose));
            RelXml.StringTag(sb, indent, "Unk55", RelXml.HashString(Unk55));
            RelXml.StringTag(sb, indent, "Unk56", RelXml.HashString(Unk56));
            RelXml.StringTag(sb, indent, "Unk57", RelXml.HashString(Unk57));
            RelXml.StringTag(sb, indent, "Unk58", RelXml.HashString(Unk58));
            RelXml.StringTag(sb, indent, "SubCreaks", RelXml.HashString(SubCreaks));
            RelXml.StringTag(sb, indent, "WaveHitBigAir", RelXml.HashString(WaveHitBigAir));
            RelXml.ValueTag(sb, indent, "Unk61", FloatUtil.ToString(Unk61));
            RelXml.StringTag(sb, indent, "Unk62", RelXml.HashString(Unk62));
            RelXml.StringTag(sb, indent, "Unk63", RelXml.HashString(Unk63));

        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Engine = XmlRel.GetHash(Xml.GetChildInnerText(node, "Engine"));
            EngineVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineVolume"));
            EnginePitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "EnginePitch"));
            Engine2 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Engine2"));
            Engine2Volume = XmlRel.GetHash(Xml.GetChildInnerText(node, "Engine2Volume"));
            Engine2Pitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "Engine2Pitch"));
            EngineLowReso = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineLowReso"));
            EngineLowResoVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineLowResoVolume"));
            EngineLowResoPitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineLowResoPitch"));
            EngineIdleLoop = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineIdleLoop"));
            EngineIdleVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineIdleVolume"));
            EngineIdlePitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineIdlePitch"));
            WaterTurbulence = XmlRel.GetHash(Xml.GetChildInnerText(node, "WaterTurbulence"));
            WaterTurbulenceVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "WaterTurbulenceVolume"));
            Unk15 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk15"));
            Unk16 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk16"));
            Unk17 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk17"));
            Unk18 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk18"));
            PoliceScannerParams = XmlRel.GetHash(Xml.GetChildInnerText(node, "PoliceScannerParams"));
            Unk20 = Xml.GetChildIntAttribute(node, "Unk20", "value");
            Horn = XmlRel.GetHash(Xml.GetChildInnerText(node, "Horn"));
            Ignition = XmlRel.GetHash(Xml.GetChildInnerText(node, "Ignition"));
            Shutdown = XmlRel.GetHash(Xml.GetChildInnerText(node, "Shutdown"));
            Unk24 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk24"));
            EngineSubmix = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineSubmix"));
            EngineSubmixPreset = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineSubmixPreset"));
            ExhaustSubmix = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustSubmix"));
            ExhaustSubmixPreset = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustSubmixPreset"));
            Collision = XmlRel.GetHash(Xml.GetChildInnerText(node, "Collision"));
            Unk30 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk30"));
            Unk31 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk31"));
            WaveHitMedium = XmlRel.GetHash(Xml.GetChildInnerText(node, "WaveHitMedium"));
            Unk33 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk33"));
            IdleHullSlap = XmlRel.GetHash(Xml.GetChildInnerText(node, "IdleHullSlap"));
            Unk35 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk35"));
            EngineGranular = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineGranular"));
            BankSpray = XmlRel.GetHash(Xml.GetChildInnerText(node, "BankSpray"));
            Ignition2 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Ignition2"));
            Startup = XmlRel.GetHash(Xml.GetChildInnerText(node, "Startup"));
            Unk40 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk40"));
            SubTurn = XmlRel.GetHash(Xml.GetChildInnerText(node, "SubTurn"));
            Unk42 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk42"));
            Unk43 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk43"));
            Unk44 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk44"));
            SandSkid = XmlRel.GetHash(Xml.GetChildInnerText(node, "SandSkid"));
            Unk46 = Xml.GetChildFloatAttribute(node, "Unk46", "value");
            Unk47 = Xml.GetChildFloatAttribute(node, "Unk47", "value");
            Unk48 = Xml.GetChildFloatAttribute(node, "Unk48", "value");
            Unk49 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk49"));
            Hull = XmlRel.GetHash(Xml.GetChildInnerText(node, "Hull"));
            Unk51 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk51"));
            Fire = XmlRel.GetHash(Xml.GetChildInnerText(node, "Fire"));
            DoorOpen = XmlRel.GetHash(Xml.GetChildInnerText(node, "DoorOpen"));
            DoorClose = XmlRel.GetHash(Xml.GetChildInnerText(node, "DoorClose"));
            Unk55 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk55"));
            Unk56 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk56"));
            Unk57 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk57"));
            Unk58 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk58"));
            SubCreaks = XmlRel.GetHash(Xml.GetChildInnerText(node, "SubCreaks"));
            WaveHitBigAir = XmlRel.GetHash(Xml.GetChildInnerText(node, "WaveHitBigAir"));
            Unk61 = Xml.GetChildFloatAttribute(node, "Unk61", "value");
            Unk62 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk62"));
            Unk63 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk63"));

        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { EngineVolume, EnginePitch, Engine2Volume, Engine2Pitch, EngineLowResoVolume, EngineLowResoPitch, EngineIdleVolume, EngineIdlePitch,
                WaterTurbulenceVolume, Unk35, Unk40, Unk42, Unk43, Unk44 };
        }
        public override MetaHash[] GetSynthHashes()
        {
            return new[] { EngineSubmix, EngineSubmixPreset, ExhaustSubmix, ExhaustSubmixPreset };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Engine, Engine2, EngineLowReso, EngineIdleLoop, WaterTurbulence, Unk16, Unk17, Unk18, Horn, Ignition, Shutdown, Unk30, Unk31,
                WaveHitMedium, IdleHullSlap, BankSpray, Ignition2, Startup, SubTurn, SandSkid, Unk49, Hull, Unk51, Fire, DoorOpen, DoorClose,
                Unk55, Unk56, Unk57, Unk58, SubCreaks, WaveHitBigAir, Unk62, Unk63 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { PoliceScannerParams, Collision, EngineGranular };
        }
    }
    [TC(typeof(EXP))] public class Dat151Bicycle : Dat151RelData
    {
        public MetaHash Chain { get; set; }
        public MetaHash Sprocket { get; set; }
        public MetaHash Pedal { get; set; }
        public MetaHash GearChange { get; set; }
        public float Unk04 { get; set; }
        public float Unk05 { get; set; }
        public MetaHash SuspensionUp { get; set; }
        public MetaHash SuspensionDown { get; set; }
        public float Unk08 { get; set; }
        public float Unk09 { get; set; }
        public MetaHash JumpLand1 { get; set; }
        public MetaHash JumpLand2 { get; set; }
        public int Unk12 { get; set; }
        public int Unk13 { get; set; }
        public MetaHash Collision { get; set; }
        public MetaHash Bell { get; set; }
        public MetaHash Unk16 { get; set; }
        public MetaHash Unk17 { get; set; }

        public Dat151Bicycle(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Bicycle;
            TypeID = (byte)Type;
        }
        public Dat151Bicycle(RelData d, BinaryReader br) : base(d, br)
        {
            Chain = br.ReadUInt32();
            Sprocket = br.ReadUInt32();
            Pedal = br.ReadUInt32();
            GearChange = br.ReadUInt32();
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadSingle();
            SuspensionUp = br.ReadUInt32();
            SuspensionDown = br.ReadUInt32();
            Unk08 = br.ReadSingle();
            Unk09 = br.ReadSingle();
            JumpLand1 = br.ReadUInt32();
            JumpLand2 = br.ReadUInt32();
            Unk12 = br.ReadInt32();
            Unk13 = br.ReadInt32();
            Collision = br.ReadUInt32();
            Bell = br.ReadUInt32();
            Unk16 = br.ReadUInt32();
            Unk17 = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Chain);
            bw.Write(Sprocket);
            bw.Write(Pedal);
            bw.Write(GearChange);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(SuspensionUp);
            bw.Write(SuspensionDown);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(JumpLand1);
            bw.Write(JumpLand2);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Collision);
            bw.Write(Bell);
            bw.Write(Unk16);
            bw.Write(Unk17);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Chain", RelXml.HashString(Chain));
            RelXml.StringTag(sb, indent, "Sprocket", RelXml.HashString(Sprocket));
            RelXml.StringTag(sb, indent, "Pedal", RelXml.HashString(Pedal));
            RelXml.StringTag(sb, indent, "GearChange", RelXml.HashString(GearChange));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.StringTag(sb, indent, "SuspensionUp", RelXml.HashString(SuspensionUp));
            RelXml.StringTag(sb, indent, "SuspensionDown", RelXml.HashString(SuspensionDown));
            RelXml.ValueTag(sb, indent, "Unk08", FloatUtil.ToString(Unk08));
            RelXml.ValueTag(sb, indent, "Unk09", FloatUtil.ToString(Unk09));
            RelXml.StringTag(sb, indent, "JumpLand1", RelXml.HashString(JumpLand1));
            RelXml.StringTag(sb, indent, "JumpLand2", RelXml.HashString(JumpLand2));
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.ToString());
            RelXml.ValueTag(sb, indent, "Unk13", Unk13.ToString());
            RelXml.StringTag(sb, indent, "Collision", RelXml.HashString(Collision));
            RelXml.StringTag(sb, indent, "Bell", RelXml.HashString(Bell));
            RelXml.StringTag(sb, indent, "Unk16", RelXml.HashString(Unk16));
            RelXml.StringTag(sb, indent, "Unk17", RelXml.HashString(Unk17));
        }
        public override void ReadXml(XmlNode node)
        {
            Chain = XmlRel.GetHash(Xml.GetChildInnerText(node, "Chain"));
            Sprocket = XmlRel.GetHash(Xml.GetChildInnerText(node, "Sprocket"));
            Pedal = XmlRel.GetHash(Xml.GetChildInnerText(node, "Pedal"));
            GearChange = XmlRel.GetHash(Xml.GetChildInnerText(node, "GearChange"));
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            SuspensionUp = XmlRel.GetHash(Xml.GetChildInnerText(node, "SuspensionUp"));
            SuspensionDown = XmlRel.GetHash(Xml.GetChildInnerText(node, "SuspensionDown"));
            Unk08 = Xml.GetChildFloatAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildFloatAttribute(node, "Unk09", "value");
            JumpLand1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "JumpLand1"));
            JumpLand2 = XmlRel.GetHash(Xml.GetChildInnerText(node, "JumpLand2"));
            Unk12 = Xml.GetChildIntAttribute(node, "Unk12", "value");
            Unk13 = Xml.GetChildIntAttribute(node, "Unk13", "value");
            Collision = XmlRel.GetHash(Xml.GetChildInnerText(node, "Collision"));
            Bell = XmlRel.GetHash(Xml.GetChildInnerText(node, "Bell"));
            Unk16 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk16"));
            Unk17 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk17"));
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Chain, Sprocket, Pedal, GearChange, SuspensionUp, SuspensionDown, JumpLand1, JumpLand2, Bell, Unk16, Unk17 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { Collision };
        }
    }
    [TC(typeof(EXP))] public class Dat151Aeroplane : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public MetaHash Engine { get; set; }//engine loop
        public MetaHash Exhaust { get; set; }//exhaust loop
        public MetaHash Idle { get; set; }//idle loop
        public MetaHash Distance { get; set; }//distance loop
        public MetaHash Propeller { get; set; }//propellor loop
        public MetaHash Banking { get; set; }//banking loop
        public short Unk07 { get; set; }
        public short Unk08 { get; set; }
        public short Unk09 { get; set; }
        public short Unk10 { get; set; }
        public short Unk11 { get; set; }
        public short Unk12 { get; set; }
        public short Unk13 { get; set; }
        public short Unk14 { get; set; }
        public short Unk15 { get; set; }
        public short Unk16 { get; set; }
        public MetaHash Unk17 { get; set; }//curve
        public MetaHash Unk18 { get; set; }//curve
        public MetaHash Unk19 { get; set; }//same as Unk17
        public MetaHash Unk20 { get; set; }//same as Unk18
        public MetaHash Unk21 { get; set; }//curve
        public MetaHash Unk22 { get; set; }//curve
        public MetaHash Unk23 { get; set; }//curve
        public MetaHash Unk24 { get; set; }//curve
        public MetaHash Unk25 { get; set; }//curve
        public MetaHash Unk26 { get; set; }//curve
        public MetaHash Unk27 { get; set; }//curve
        public MetaHash StallWarning { get; set; }
        public MetaHash DoorOpen { get; set; }//door open
        public MetaHash DoorClose { get; set; }//door close
        public MetaHash DoorLimit { get; set; }
        public MetaHash GearDeploy { get; set; }
        public MetaHash GearRetract { get; set; }
        public MetaHash Startup { get; set; }//startup
        public MetaHash TyreLand { get; set; }//tyre_land_random
        public MetaHash Unk36 { get; set; }
        public MetaHash Unk37 { get; set; }
        public MetaHash Unk38 { get; set; }
        public MetaHash Afterburner { get; set; }//afterburner
        public int Unk40 { get; set; }
        public MetaHash Unk41 { get; set; }//curve
        public MetaHash PropTransAndEq { get; set; }
        public MetaHash PropTransAndEqPreset { get; set; }
        public MetaHash Unk44 { get; set; }//0
        public MetaHash Unk45 { get; set; }//0
        public MetaHash Unk46 { get; set; }//environment
        public MetaHash Unk47 { get; set; }//environment
        public MetaHash Unk48 { get; set; }//breakdown
        public MetaHash Unk49 { get; set; }
        public MetaHash Unk50 { get; set; }//curve
        public short Unk51 { get; set; }
        public short Unk52 { get; set; }
        public short Unk53 { get; set; }
        public short Unk54 { get; set; }
        public float Unk55 { get; set; }
        public MetaHash Rudder { get; set; }//rudder
        public MetaHash WingFlap { get; set; }
        public MetaHash TailFlap { get; set; }
        public MetaHash DoorOpenStart { get; set; }//door open start
        public MetaHash DoorCloseStart { get; set; }//door close start
        public MetaHash Collision { get; set; }
        public MetaHash Fire { get; set; }
        public MetaHash EngineDamage { get; set; }
        public int Unk64 { get; set; }
        public MetaHash SuspensionUp { get; set; }
        public MetaHash SuspensionDown { get; set; }
        public float Unk67 { get; set; }
        public float Unk68 { get; set; }
        public MetaHash Unk69 { get; set; }//curve
        public MetaHash Unk70 { get; set; }//curve
        public MetaHash Unk71 { get; set; }//curve
        public MetaHash Unk72 { get; set; }
        public MetaHash Damage { get; set; }//damage
        public MetaHash Unk74 { get; set; }//curve
        public float Unk75 { get; set; }
        public MetaHash Unk76 { get; set; }
        public MetaHash Divebomb { get; set; }
        public short Unk78 { get; set; }//1
        public short Unk79 { get; set; }//1
        public short Unk80 { get; set; }//750
        public short Unk81 { get; set; }//1
        public float Unk82 { get; set; }
        public float Unk83 { get; set; }
        public float Unk84 { get; set; }
        public MetaHash ThrustBank { get; set; }//thrust bank
        public MetaHash Unk86 { get; set; }

        public MetaHash Unk87 { get; set; }
        public MetaHash Unk88 { get; set; }
        public MetaHash Unk89 { get; set; }//0
        public MetaHash Unk90 { get; set; }
        public MetaHash Unk91 { get; set; }
        public float Unk92 { get; set; }
        public MetaHash Unk93 { get; set; }//0
        public MetaHash Unk94 { get; set; }
        public MetaHash Unk95 { get; set; }//curve
        public MetaHash Unk96 { get; set; }

        public int Version { get; set; }

        public Dat151Aeroplane(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Aeroplane;
            TypeID = (byte)Type;
        }
        public Dat151Aeroplane(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Engine = br.ReadUInt32();
            Exhaust = br.ReadUInt32();
            Idle = br.ReadUInt32();
            Distance = br.ReadUInt32();
            Propeller = br.ReadUInt32();
            Banking = br.ReadUInt32();
            Unk07 = br.ReadInt16();
            Unk08 = br.ReadInt16();
            Unk09 = br.ReadInt16();
            Unk10 = br.ReadInt16();
            Unk11 = br.ReadInt16();
            Unk12 = br.ReadInt16();
            Unk13 = br.ReadInt16();
            Unk14 = br.ReadInt16();
            Unk15 = br.ReadInt16();
            Unk16 = br.ReadInt16();
            Unk17 = br.ReadUInt32();
            Unk18 = br.ReadUInt32();
            Unk19 = br.ReadUInt32();
            Unk20 = br.ReadUInt32();
            Unk21 = br.ReadUInt32();
            Unk22 = br.ReadUInt32();
            Unk23 = br.ReadUInt32();
            Unk24 = br.ReadUInt32();
            Unk25 = br.ReadUInt32();
            Unk26 = br.ReadUInt32();
            Unk27 = br.ReadUInt32();
            StallWarning = br.ReadUInt32();
            DoorOpen = br.ReadUInt32();
            DoorClose = br.ReadUInt32();
            DoorLimit = br.ReadUInt32();
            GearDeploy = br.ReadUInt32();
            GearRetract = br.ReadUInt32();
            Startup = br.ReadUInt32();
            TyreLand = br.ReadUInt32();
            Unk36 = br.ReadUInt32();
            Unk37 = br.ReadUInt32();
            Unk38 = br.ReadUInt32();
            Afterburner = br.ReadUInt32();
            Unk40 = br.ReadInt32();
            Unk41 = br.ReadUInt32();
            PropTransAndEq = br.ReadUInt32();
            PropTransAndEqPreset = br.ReadUInt32();
            Unk44 = br.ReadUInt32();
            Unk45 = br.ReadUInt32();
            Unk46 = br.ReadUInt32();
            Unk47 = br.ReadUInt32();
            Unk48 = br.ReadUInt32();
            Unk49 = br.ReadUInt32();
            Unk50 = br.ReadUInt32();
            Unk51 = br.ReadInt16();
            Unk52 = br.ReadInt16();
            Unk53 = br.ReadInt16();
            Unk54 = br.ReadInt16();
            Unk55 = br.ReadSingle();
            Rudder = br.ReadUInt32();
            WingFlap = br.ReadUInt32();
            TailFlap = br.ReadUInt32();
            DoorOpenStart = br.ReadUInt32();
            DoorCloseStart = br.ReadUInt32();
            Collision = br.ReadUInt32();
            Fire = br.ReadUInt32();
            EngineDamage = br.ReadUInt32();
            Unk64 = br.ReadInt32();
            SuspensionUp = br.ReadUInt32();
            SuspensionDown = br.ReadUInt32();
            Unk67 = br.ReadSingle();
            Unk68 = br.ReadSingle();
            Unk69 = br.ReadUInt32();
            Unk70 = br.ReadUInt32();
            Unk71 = br.ReadUInt32();
            Unk72 = br.ReadUInt32();
            Damage = br.ReadUInt32();
            Unk74 = br.ReadUInt32();
            Unk75 = br.ReadSingle();
            Unk76 = br.ReadUInt32();
            Divebomb = br.ReadUInt32();
            Unk78 = br.ReadInt16();
            Unk79 = br.ReadInt16();
            Unk80 = br.ReadInt16();
            Unk81 = br.ReadInt16();
            Unk82 = br.ReadSingle();
            Unk83 = br.ReadSingle();
            Unk84 = br.ReadSingle();
            ThrustBank = br.ReadUInt32();
            Unk86 = br.ReadUInt32();

            Version = 0;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft == 40)
            {
                Version = 1;

                Unk87 = br.ReadUInt32();
                Unk88 = br.ReadUInt32();
                Unk89 = br.ReadUInt32();
                Unk90 = br.ReadUInt32();
                Unk91 = br.ReadUInt32();
                Unk92 = br.ReadSingle();
                Unk93 = br.ReadUInt32();
                Unk94 = br.ReadUInt32();
                Unk95 = br.ReadUInt32();
                Unk96 = br.ReadUInt32();
            }


            bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Engine);
            bw.Write(Exhaust);
            bw.Write(Idle);
            bw.Write(Distance);
            bw.Write(Propeller);
            bw.Write(Banking);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
            bw.Write(Unk19);
            bw.Write(Unk20);
            bw.Write(Unk21);
            bw.Write(Unk22);
            bw.Write(Unk23);
            bw.Write(Unk24);
            bw.Write(Unk25);
            bw.Write(Unk26);
            bw.Write(Unk27);
            bw.Write(StallWarning);
            bw.Write(DoorOpen);
            bw.Write(DoorClose);
            bw.Write(DoorLimit);
            bw.Write(GearDeploy);
            bw.Write(GearRetract);
            bw.Write(Startup);
            bw.Write(TyreLand);
            bw.Write(Unk36);
            bw.Write(Unk37);
            bw.Write(Unk38);
            bw.Write(Afterburner);
            bw.Write(Unk40);
            bw.Write(Unk41);
            bw.Write(PropTransAndEq);
            bw.Write(PropTransAndEqPreset);
            bw.Write(Unk44);
            bw.Write(Unk45);
            bw.Write(Unk46);
            bw.Write(Unk47);
            bw.Write(Unk48);
            bw.Write(Unk49);
            bw.Write(Unk50);
            bw.Write(Unk51);
            bw.Write(Unk52);
            bw.Write(Unk53);
            bw.Write(Unk54);
            bw.Write(Unk55);
            bw.Write(Rudder);
            bw.Write(WingFlap);
            bw.Write(TailFlap);
            bw.Write(DoorOpenStart);
            bw.Write(DoorCloseStart);
            bw.Write(Collision);
            bw.Write(Fire);
            bw.Write(EngineDamage);
            bw.Write(Unk64);
            bw.Write(SuspensionUp);
            bw.Write(SuspensionDown);
            bw.Write(Unk67);
            bw.Write(Unk68);
            bw.Write(Unk69);
            bw.Write(Unk70);
            bw.Write(Unk71);
            bw.Write(Unk72);
            bw.Write(Damage);
            bw.Write(Unk74);
            bw.Write(Unk75);
            bw.Write(Unk76);
            bw.Write(Divebomb);
            bw.Write(Unk78);
            bw.Write(Unk79);
            bw.Write(Unk80);
            bw.Write(Unk81);
            bw.Write(Unk82);
            bw.Write(Unk83);
            bw.Write(Unk84);
            bw.Write(ThrustBank);
            bw.Write(Unk86);

            if (Version >= 1)
            {
                bw.Write(Unk87);
                bw.Write(Unk88);
                bw.Write(Unk89);
                bw.Write(Unk90);
                bw.Write(Unk91);
                bw.Write(Unk92);
                bw.Write(Unk93);
                bw.Write(Unk94);
                bw.Write(Unk95);
                bw.Write(Unk96);
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Version", Version.ToString()); //CW invention, not an actual field!
            RelXml.StringTag(sb, indent, "Engine", RelXml.HashString(Engine));
            RelXml.StringTag(sb, indent, "Exhaust", RelXml.HashString(Exhaust));
            RelXml.StringTag(sb, indent, "Idle", RelXml.HashString(Idle));
            RelXml.StringTag(sb, indent, "Distance", RelXml.HashString(Distance));
            RelXml.StringTag(sb, indent, "Propeller", RelXml.HashString(Propeller));
            RelXml.StringTag(sb, indent, "Banking", RelXml.HashString(Banking));
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.ValueTag(sb, indent, "Unk11", Unk11.ToString());
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.ToString());
            RelXml.ValueTag(sb, indent, "Unk13", Unk13.ToString());
            RelXml.ValueTag(sb, indent, "Unk14", Unk14.ToString());
            RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.StringTag(sb, indent, "Unk17", RelXml.HashString(Unk17));
            RelXml.StringTag(sb, indent, "Unk18", RelXml.HashString(Unk18));
            RelXml.StringTag(sb, indent, "Unk19", RelXml.HashString(Unk19));
            RelXml.StringTag(sb, indent, "Unk20", RelXml.HashString(Unk20));
            RelXml.StringTag(sb, indent, "Unk21", RelXml.HashString(Unk21));
            RelXml.StringTag(sb, indent, "Unk22", RelXml.HashString(Unk22));
            RelXml.StringTag(sb, indent, "Unk23", RelXml.HashString(Unk23));
            RelXml.StringTag(sb, indent, "Unk24", RelXml.HashString(Unk24));
            RelXml.StringTag(sb, indent, "Unk25", RelXml.HashString(Unk25));
            RelXml.StringTag(sb, indent, "Unk26", RelXml.HashString(Unk26));
            RelXml.StringTag(sb, indent, "Unk27", RelXml.HashString(Unk27));
            RelXml.StringTag(sb, indent, "StallWarning", RelXml.HashString(StallWarning));
            RelXml.StringTag(sb, indent, "DoorOpen", RelXml.HashString(DoorOpen));
            RelXml.StringTag(sb, indent, "DoorClose", RelXml.HashString(DoorClose));
            RelXml.StringTag(sb, indent, "DoorLimit", RelXml.HashString(DoorLimit));
            RelXml.StringTag(sb, indent, "GearDeploy", RelXml.HashString(GearDeploy));
            RelXml.StringTag(sb, indent, "GearRetract", RelXml.HashString(GearRetract));
            RelXml.StringTag(sb, indent, "Startup", RelXml.HashString(Startup));
            RelXml.StringTag(sb, indent, "TyreLand", RelXml.HashString(TyreLand));
            RelXml.StringTag(sb, indent, "Unk36", RelXml.HashString(Unk36));
            RelXml.StringTag(sb, indent, "Unk37", RelXml.HashString(Unk37));
            RelXml.StringTag(sb, indent, "Unk38", RelXml.HashString(Unk38));
            RelXml.StringTag(sb, indent, "Afterburner", RelXml.HashString(Afterburner));
            RelXml.ValueTag(sb, indent, "Unk40", Unk40.ToString());
            RelXml.StringTag(sb, indent, "Unk41", RelXml.HashString(Unk41));
            RelXml.StringTag(sb, indent, "PropTransAndEq", RelXml.HashString(PropTransAndEq));
            RelXml.StringTag(sb, indent, "PropTransAndEqPreset", RelXml.HashString(PropTransAndEqPreset));
            RelXml.StringTag(sb, indent, "Unk44", RelXml.HashString(Unk44));
            RelXml.StringTag(sb, indent, "Unk45", RelXml.HashString(Unk45));
            RelXml.StringTag(sb, indent, "Unk46", RelXml.HashString(Unk46));
            RelXml.StringTag(sb, indent, "Unk47", RelXml.HashString(Unk47));
            RelXml.StringTag(sb, indent, "Unk48", RelXml.HashString(Unk48));
            RelXml.StringTag(sb, indent, "Unk49", RelXml.HashString(Unk49));
            RelXml.StringTag(sb, indent, "Unk50", RelXml.HashString(Unk50));
            RelXml.ValueTag(sb, indent, "Unk51", Unk51.ToString());
            RelXml.ValueTag(sb, indent, "Unk52", Unk52.ToString());
            RelXml.ValueTag(sb, indent, "Unk53", Unk53.ToString());
            RelXml.ValueTag(sb, indent, "Unk54", Unk54.ToString());
            RelXml.ValueTag(sb, indent, "Unk55", FloatUtil.ToString(Unk55));
            RelXml.StringTag(sb, indent, "Rudder", RelXml.HashString(Rudder));
            RelXml.StringTag(sb, indent, "WingFlap", RelXml.HashString(WingFlap));
            RelXml.StringTag(sb, indent, "TailFlap", RelXml.HashString(TailFlap));
            RelXml.StringTag(sb, indent, "DoorOpenStart", RelXml.HashString(DoorOpenStart));
            RelXml.StringTag(sb, indent, "DoorCloseStart", RelXml.HashString(DoorCloseStart));
            RelXml.StringTag(sb, indent, "Collision", RelXml.HashString(Collision));
            RelXml.StringTag(sb, indent, "Fire", RelXml.HashString(Fire));
            RelXml.StringTag(sb, indent, "EngineDamage", RelXml.HashString(EngineDamage));
            RelXml.ValueTag(sb, indent, "Unk64", Unk64.ToString());
            RelXml.StringTag(sb, indent, "SuspensionUp", RelXml.HashString(SuspensionUp));
            RelXml.StringTag(sb, indent, "SuspensionDown", RelXml.HashString(SuspensionDown));
            RelXml.ValueTag(sb, indent, "Unk67", FloatUtil.ToString(Unk67));
            RelXml.ValueTag(sb, indent, "Unk68", FloatUtil.ToString(Unk68));
            RelXml.StringTag(sb, indent, "Unk69", RelXml.HashString(Unk69));
            RelXml.StringTag(sb, indent, "Unk70", RelXml.HashString(Unk70));
            RelXml.StringTag(sb, indent, "Unk71", RelXml.HashString(Unk71));
            RelXml.StringTag(sb, indent, "Unk72", RelXml.HashString(Unk72));
            RelXml.StringTag(sb, indent, "Damage", RelXml.HashString(Damage));
            RelXml.StringTag(sb, indent, "Unk74", RelXml.HashString(Unk74));
            RelXml.ValueTag(sb, indent, "Unk75", FloatUtil.ToString(Unk75));
            RelXml.StringTag(sb, indent, "Unk76", RelXml.HashString(Unk76));
            RelXml.StringTag(sb, indent, "Divebomb", RelXml.HashString(Divebomb));
            RelXml.ValueTag(sb, indent, "Unk78", Unk78.ToString());
            RelXml.ValueTag(sb, indent, "Unk79", Unk79.ToString());
            RelXml.ValueTag(sb, indent, "Unk80", Unk80.ToString());
            RelXml.ValueTag(sb, indent, "Unk81", Unk81.ToString());
            RelXml.ValueTag(sb, indent, "Unk82", FloatUtil.ToString(Unk82));
            RelXml.ValueTag(sb, indent, "Unk83", FloatUtil.ToString(Unk83));
            RelXml.ValueTag(sb, indent, "Unk84", FloatUtil.ToString(Unk84));
            RelXml.StringTag(sb, indent, "ThrustBank", RelXml.HashString(ThrustBank));
            RelXml.StringTag(sb, indent, "Unk86", RelXml.HashString(Unk86));

            if (Version >= 1)
            {
                RelXml.StringTag(sb, indent, "Unk87", RelXml.HashString(Unk87));
                RelXml.StringTag(sb, indent, "Unk88", RelXml.HashString(Unk88));
                RelXml.StringTag(sb, indent, "Unk89", RelXml.HashString(Unk89));
                RelXml.StringTag(sb, indent, "Unk90", RelXml.HashString(Unk90));
                RelXml.StringTag(sb, indent, "Unk91", RelXml.HashString(Unk91));
                RelXml.ValueTag(sb, indent, "Unk92", FloatUtil.ToString(Unk92));
                RelXml.StringTag(sb, indent, "Unk93", RelXml.HashString(Unk93));
                RelXml.StringTag(sb, indent, "Unk94", RelXml.HashString(Unk94));
                RelXml.StringTag(sb, indent, "Unk95", RelXml.HashString(Unk95));
                RelXml.StringTag(sb, indent, "Unk96", RelXml.HashString(Unk96));
            }

        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Version = Xml.GetChildIntAttribute(node, "Version", "value");
            Engine = XmlRel.GetHash(Xml.GetChildInnerText(node, "Engine"));
            Exhaust = XmlRel.GetHash(Xml.GetChildInnerText(node, "Exhaust"));
            Idle = XmlRel.GetHash(Xml.GetChildInnerText(node, "Idle"));
            Distance = XmlRel.GetHash(Xml.GetChildInnerText(node, "Distance"));
            Propeller = XmlRel.GetHash(Xml.GetChildInnerText(node, "Propeller"));
            Banking = XmlRel.GetHash(Xml.GetChildInnerText(node, "Banking"));
            Unk07 = (short)Xml.GetChildIntAttribute(node, "Unk07", "value");
            Unk08 = (short)Xml.GetChildIntAttribute(node, "Unk08", "value");
            Unk09 = (short)Xml.GetChildIntAttribute(node, "Unk09", "value");
            Unk10 = (short)Xml.GetChildIntAttribute(node, "Unk10", "value");
            Unk11 = (short)Xml.GetChildIntAttribute(node, "Unk11", "value");
            Unk12 = (short)Xml.GetChildIntAttribute(node, "Unk12", "value");
            Unk13 = (short)Xml.GetChildIntAttribute(node, "Unk13", "value");
            Unk14 = (short)Xml.GetChildIntAttribute(node, "Unk14", "value");
            Unk15 = (short)Xml.GetChildIntAttribute(node, "Unk15", "value");
            Unk16 = (short)Xml.GetChildIntAttribute(node, "Unk16", "value");
            Unk17 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk17"));
            Unk18 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk18"));
            Unk19 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk19"));
            Unk20 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk20"));
            Unk21 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk21"));
            Unk22 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk22"));
            Unk23 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk23"));
            Unk24 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk24"));
            Unk25 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk25"));
            Unk26 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk26"));
            Unk27 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk27"));
            StallWarning = XmlRel.GetHash(Xml.GetChildInnerText(node, "StallWarning"));
            DoorOpen = XmlRel.GetHash(Xml.GetChildInnerText(node, "DoorOpen"));
            DoorClose = XmlRel.GetHash(Xml.GetChildInnerText(node, "DoorClose"));
            DoorLimit = XmlRel.GetHash(Xml.GetChildInnerText(node, "DoorLimit"));
            GearDeploy = XmlRel.GetHash(Xml.GetChildInnerText(node, "GearDeploy"));
            GearRetract = XmlRel.GetHash(Xml.GetChildInnerText(node, "GearRetract"));
            Startup = XmlRel.GetHash(Xml.GetChildInnerText(node, "Startup"));
            TyreLand = XmlRel.GetHash(Xml.GetChildInnerText(node, "TyreLand"));
            Unk36 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk36"));
            Unk37 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk37"));
            Unk38 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk38"));
            Afterburner = XmlRel.GetHash(Xml.GetChildInnerText(node, "Afterburner"));
            Unk40 = Xml.GetChildIntAttribute(node, "Unk40", "value");
            Unk41 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk41"));
            PropTransAndEq = XmlRel.GetHash(Xml.GetChildInnerText(node, "PropTransAndEq"));
            PropTransAndEqPreset = XmlRel.GetHash(Xml.GetChildInnerText(node, "PropTransAndEqPreset"));
            Unk44 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk44"));
            Unk45 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk45"));
            Unk46 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk46"));
            Unk47 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk47"));
            Unk48 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk48"));
            Unk49 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk49"));
            Unk50 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk50"));
            Unk51 = (short)Xml.GetChildIntAttribute(node, "Unk51", "value");
            Unk52 = (short)Xml.GetChildIntAttribute(node, "Unk52", "value");
            Unk53 = (short)Xml.GetChildIntAttribute(node, "Unk53", "value");
            Unk54 = (short)Xml.GetChildIntAttribute(node, "Unk54", "value");
            Unk55 = Xml.GetChildFloatAttribute(node, "Unk55", "value");
            Rudder = XmlRel.GetHash(Xml.GetChildInnerText(node, "Rudder"));
            WingFlap = XmlRel.GetHash(Xml.GetChildInnerText(node, "WingFlap"));
            TailFlap = XmlRel.GetHash(Xml.GetChildInnerText(node, "TailFlap"));
            DoorOpenStart = XmlRel.GetHash(Xml.GetChildInnerText(node, "DoorOpenStart"));
            DoorCloseStart = XmlRel.GetHash(Xml.GetChildInnerText(node, "DoorCloseStart"));
            Collision = XmlRel.GetHash(Xml.GetChildInnerText(node, "Collision"));
            Fire = XmlRel.GetHash(Xml.GetChildInnerText(node, "Fire"));
            EngineDamage = XmlRel.GetHash(Xml.GetChildInnerText(node, "EngineDamage"));
            Unk64 = Xml.GetChildIntAttribute(node, "Unk64", "value");
            SuspensionUp = XmlRel.GetHash(Xml.GetChildInnerText(node, "SuspensionUp"));
            SuspensionDown = XmlRel.GetHash(Xml.GetChildInnerText(node, "SuspensionDown"));
            Unk67 = Xml.GetChildFloatAttribute(node, "Unk67", "value");
            Unk68 = Xml.GetChildFloatAttribute(node, "Unk68", "value");
            Unk69 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk69"));
            Unk70 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk70"));
            Unk71 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk71"));
            Unk72 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk72"));
            Damage = XmlRel.GetHash(Xml.GetChildInnerText(node, "Damage"));
            Unk74 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk74"));
            Unk75 = Xml.GetChildFloatAttribute(node, "Unk75", "value");
            Unk76 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk76"));
            Divebomb = XmlRel.GetHash(Xml.GetChildInnerText(node, "Divebomb"));
            Unk78 = (short)Xml.GetChildIntAttribute(node, "Unk78", "value");
            Unk79 = (short)Xml.GetChildIntAttribute(node, "Unk79", "value");
            Unk80 = (short)Xml.GetChildIntAttribute(node, "Unk80", "value");
            Unk81 = (short)Xml.GetChildIntAttribute(node, "Unk81", "value");
            Unk82 = Xml.GetChildFloatAttribute(node, "Unk82", "value");
            Unk83 = Xml.GetChildFloatAttribute(node, "Unk83", "value");
            Unk84 = Xml.GetChildFloatAttribute(node, "Unk84", "value");
            ThrustBank = XmlRel.GetHash(Xml.GetChildInnerText(node, "ThrustBank"));
            Unk86 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk86"));

            if (Version >= 1)
            {
                Unk87 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk87"));
                Unk88 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk88"));
                Unk89 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk89"));
                Unk90 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk90"));
                Unk91 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk91"));
                Unk92 = Xml.GetChildFloatAttribute(node, "Unk92", "value");
                Unk93 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk93"));
                Unk94 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk94"));
                Unk95 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk95"));
                Unk96 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk96"));

            }


        }
        public override MetaHash[] GetSynthHashes()
        {
            return new[] { PropTransAndEq, PropTransAndEqPreset };
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { Unk17, Unk18, Unk19, Unk20, Unk21, Unk22, Unk23, Unk24, Unk25, Unk26, Unk27, Unk36, Unk37, Unk38, Unk41, Unk50,
                Unk69, Unk70, Unk71, Unk74, Unk95 };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Engine, Exhaust, Idle, Distance, Propeller, Banking, StallWarning, DoorOpen, DoorClose, DoorLimit, GearDeploy, GearRetract,
                Startup, TyreLand, Afterburner, Unk46, Unk47, Unk48, Unk49, Rudder, WingFlap, TailFlap, DoorOpenStart, DoorCloseStart, Fire, EngineDamage,
                SuspensionUp, SuspensionDown, Unk72, Damage, Unk76, Divebomb, ThrustBank, Unk86, Unk87, Unk88, Unk90, Unk91, Unk94, Unk96 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { Collision };
        }
    }
    [TC(typeof(EXP))] public class Dat151Helicopter : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public MetaHash MainRotor { get; set; }
        public MetaHash TailRotor { get; set; }//rear_rotor_loop_vb
        public MetaHash Exhaust { get; set; }//exhaust_loop_vb
        public MetaHash Engine { get; set; }
        public MetaHash InternalCabinTone { get; set; }
        public float Unk06 { get; set; }
        public MetaHash BankAngleVolume { get; set; }
        public MetaHash BankThrottleVolume { get; set; }
        public MetaHash BankThrottlePitch { get; set; }
        public MetaHash RotorThrottleVolume { get; set; }
        public MetaHash RotorThrottlePitch { get; set; }
        public MetaHash RotorThrottleGap { get; set; }
        public MetaHash TailRotorThrottleVolume { get; set; }
        public MetaHash ExhaustThrottleVolume { get; set; }
        public MetaHash ExhaustThrottlePitch { get; set; }
        public short Unk16 { get; set; }
        public short Unk17 { get; set; }
        public short Unk18 { get; set; }
        public short Unk19 { get; set; }
        public short Unk20 { get; set; }
        public short Unk21 { get; set; }
        public short Unk22 { get; set; }
        public short Unk23 { get; set; }
        public short Unk24 { get; set; }
        public short Unk25 { get; set; }
        public MetaHash ThrottleResonance1 { get; set; }
        public MetaHash ThrottleResonance2 { get; set; }
        public MetaHash BankingResonance { get; set; }
        public MetaHash RotorStartupVolume { get; set; }
        public MetaHash BladeStartupVolume { get; set; }
        public MetaHash RotorStartupPitch { get; set; }
        public MetaHash RearRotorStartupVolume { get; set; }
        public MetaHash ExhaustStartupVolume { get; set; }
        public MetaHash RotorStartupGap { get; set; }
        public MetaHash Startup { get; set; }//startup
        public short Unk36 { get; set; }
        public short Unk37 { get; set; }
        public short Unk38 { get; set; }
        public short Unk39 { get; set; }
        public int Unk40 { get; set; }
        public MetaHash Unk41 { get; set; }
        public MetaHash Unk42 { get; set; }
        public MetaHash PoliceScannerCategory { get; set; }
        public MetaHash PoliceScannerParams { get; set; }//scanner_params
        public int RadioFlags { get; set; }
        public MetaHash DoorOpen { get; set; }
        public MetaHash DoorClose { get; set; }
        public MetaHash DoorLimit { get; set; }
        public MetaHash Damage { get; set; }//damage_loop_vb
        public MetaHash Unk50 { get; set; }//curve
        public int Unk51 { get; set; }
        public MetaHash Unk52 { get; set; }//0
        public MetaHash Unk53 { get; set; }//0
        public MetaHash Unk54 { get; set; }//0
        public MetaHash Unk55 { get; set; }//0
        public MetaHash Unk56 { get; set; }//environment
        public MetaHash Unk57 { get; set; }//environment
        public MetaHash RotorBass { get; set; }
        public MetaHash Unk59 { get; set; }//curve
        public MetaHash Collision { get; set; }//vehicle_collision
        public MetaHash Fire { get; set; }
        public MetaHash Distant { get; set; }//distant_loop
        public MetaHash Unk63 { get; set; }
        public MetaHash Unk64 { get; set; }
        public MetaHash Unk65 { get; set; }
        public MetaHash Unk66 { get; set; }
        public MetaHash SuspensionUp { get; set; }//suspension_up
        public MetaHash SuspensionDown { get; set; }//suspension_down
        public float Unk69 { get; set; }
        public float Unk70 { get; set; }
        public MetaHash DamageOneShots { get; set; }//damage_oneshots
        public MetaHash DamageWarning { get; set; }//damage_warning
        public MetaHash TailBreak { get; set; }
        public MetaHash MainRotorBreak { get; set; }
        public MetaHash TailRotorBreak { get; set; }
        public MetaHash CableDeploy { get; set; }
        public MetaHash Unk77 { get; set; }
        public MetaHash Unk78 { get; set; }
        public MetaHash AltitudeWarning { get; set; }//altitude_warning
        public MetaHash DamageVolumeCurve { get; set; }
        public MetaHash DamageVolumeCurve2 { get; set; }
        public MetaHash DamageBelow600 { get; set; }//damage_below_600_loop_vb
        public float Unk83 { get; set; }
        public float Unk84 { get; set; }
        public float Unk85 { get; set; }
        public MetaHash Jet { get; set; }//jet
        public MetaHash PlayerSwitch { get; set; }
        public MetaHash Unk88 { get; set; }

        public MetaHash Unk89 { get; set; }
        public MetaHash Unk90 { get; set; }
        public MetaHash StartupBroken { get; set; }//startup_broken

        public int Version { get; set; }


        public Dat151Helicopter(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Helicopter;
            TypeID = (byte)Type;
        }
        public Dat151Helicopter(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            MainRotor = br.ReadUInt32();
            TailRotor = br.ReadUInt32();
            Exhaust = br.ReadUInt32();
            Engine = br.ReadUInt32();
            InternalCabinTone = br.ReadUInt32();
            Unk06 = br.ReadSingle();
            BankAngleVolume = br.ReadUInt32();
            BankThrottleVolume = br.ReadUInt32();
            BankThrottlePitch = br.ReadUInt32();
            RotorThrottleVolume = br.ReadUInt32();
            RotorThrottlePitch = br.ReadUInt32();
            RotorThrottleGap = br.ReadUInt32();
            TailRotorThrottleVolume = br.ReadUInt32();
            ExhaustThrottleVolume = br.ReadUInt32();
            ExhaustThrottlePitch = br.ReadUInt32();
            Unk16 = br.ReadInt16();
            Unk17 = br.ReadInt16();
            Unk18 = br.ReadInt16();
            Unk19 = br.ReadInt16();
            Unk20 = br.ReadInt16();
            Unk21 = br.ReadInt16();
            Unk22 = br.ReadInt16();
            Unk23 = br.ReadInt16();
            Unk24 = br.ReadInt16();
            Unk25 = br.ReadInt16();
            ThrottleResonance1 = br.ReadUInt32();
            ThrottleResonance2 = br.ReadUInt32();
            BankingResonance = br.ReadUInt32();
            RotorStartupVolume = br.ReadUInt32();
            BladeStartupVolume = br.ReadUInt32();
            RotorStartupPitch = br.ReadUInt32();
            RearRotorStartupVolume = br.ReadUInt32();
            ExhaustStartupVolume = br.ReadUInt32();
            RotorStartupGap = br.ReadUInt32();
            Startup = br.ReadUInt32();
            Unk36 = br.ReadInt16();
            Unk37 = br.ReadInt16();
            Unk38 = br.ReadInt16();
            Unk39 = br.ReadInt16();
            Unk40 = br.ReadInt32();
            Unk41 = br.ReadUInt32();
            Unk42 = br.ReadUInt32();
            PoliceScannerCategory = br.ReadUInt32();
            PoliceScannerParams = br.ReadUInt32();
            RadioFlags = br.ReadInt32();
            DoorOpen = br.ReadUInt32();
            DoorClose = br.ReadUInt32();
            DoorLimit = br.ReadUInt32();
            Damage = br.ReadUInt32();
            Unk50 = br.ReadUInt32();
            Unk51 = br.ReadInt32();
            Unk52 = br.ReadUInt32();
            Unk53 = br.ReadUInt32();
            Unk54 = br.ReadUInt32();
            Unk55 = br.ReadUInt32();
            Unk56 = br.ReadUInt32();
            Unk57 = br.ReadUInt32();
            RotorBass = br.ReadUInt32();
            Unk59 = br.ReadUInt32();
            Collision = br.ReadUInt32();
            Fire = br.ReadUInt32();
            Distant = br.ReadUInt32();
            Unk63 = br.ReadUInt32();
            Unk64 = br.ReadUInt32();
            Unk65 = br.ReadUInt32();
            Unk66 = br.ReadUInt32();
            SuspensionUp = br.ReadUInt32();
            SuspensionDown = br.ReadUInt32();
            Unk69 = br.ReadSingle();
            Unk70 = br.ReadSingle();
            DamageOneShots = br.ReadUInt32();
            DamageWarning = br.ReadUInt32();
            TailBreak = br.ReadUInt32();
            MainRotorBreak = br.ReadUInt32();
            TailRotorBreak = br.ReadUInt32();
            CableDeploy = br.ReadUInt32();
            Unk77 = br.ReadUInt32();
            Unk78 = br.ReadUInt32();
            AltitudeWarning = br.ReadUInt32();
            DamageVolumeCurve = br.ReadUInt32();
            DamageVolumeCurve2 = br.ReadUInt32();
            DamageBelow600 = br.ReadUInt32();
            Unk83 = br.ReadSingle();
            Unk84 = br.ReadSingle();
            Unk85 = br.ReadSingle();
            Jet = br.ReadUInt32();
            PlayerSwitch = br.ReadUInt32();
            Unk88 = br.ReadUInt32();


            if (Unk52 != 0)
            { }
            if (Unk53 != 0)
            { }
            if (Unk54 != 0)
            { }
            if (Unk55 != 0)
            { }


            Version = 0;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft >= 12)
            {
                Version = 1;

                Unk89 = br.ReadUInt32();
                Unk90 = br.ReadUInt32();
                StartupBroken = br.ReadUInt32();
            }

            bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(MainRotor);
            bw.Write(TailRotor);
            bw.Write(Exhaust);
            bw.Write(Engine);
            bw.Write(InternalCabinTone);
            bw.Write(Unk06);
            bw.Write(BankAngleVolume);
            bw.Write(BankThrottleVolume);
            bw.Write(BankThrottlePitch);
            bw.Write(RotorThrottleVolume);
            bw.Write(RotorThrottlePitch);
            bw.Write(RotorThrottleGap);
            bw.Write(TailRotorThrottleVolume);
            bw.Write(ExhaustThrottleVolume);
            bw.Write(ExhaustThrottlePitch);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
            bw.Write(Unk19);
            bw.Write(Unk20);
            bw.Write(Unk21);
            bw.Write(Unk22);
            bw.Write(Unk23);
            bw.Write(Unk24);
            bw.Write(Unk25);
            bw.Write(ThrottleResonance1);
            bw.Write(ThrottleResonance2);
            bw.Write(BankingResonance);
            bw.Write(RotorStartupVolume);
            bw.Write(BladeStartupVolume);
            bw.Write(RotorStartupPitch);
            bw.Write(RearRotorStartupVolume);
            bw.Write(ExhaustStartupVolume);
            bw.Write(RotorStartupGap);
            bw.Write(Startup);
            bw.Write(Unk36);
            bw.Write(Unk37);
            bw.Write(Unk38);
            bw.Write(Unk39);
            bw.Write(Unk40);
            bw.Write(Unk41);
            bw.Write(Unk42);
            bw.Write(PoliceScannerCategory);
            bw.Write(PoliceScannerParams);
            bw.Write(RadioFlags);
            bw.Write(DoorOpen);
            bw.Write(DoorClose);
            bw.Write(DoorLimit);
            bw.Write(Damage);
            bw.Write(Unk50);
            bw.Write(Unk51);
            bw.Write(Unk52);
            bw.Write(Unk53);
            bw.Write(Unk54);
            bw.Write(Unk55);
            bw.Write(Unk56);
            bw.Write(Unk57);
            bw.Write(RotorBass);
            bw.Write(Unk59);
            bw.Write(Collision);
            bw.Write(Fire);
            bw.Write(Distant);
            bw.Write(Unk63);
            bw.Write(Unk64);
            bw.Write(Unk65);
            bw.Write(Unk66);
            bw.Write(SuspensionUp);
            bw.Write(SuspensionDown);
            bw.Write(Unk69);
            bw.Write(Unk70);
            bw.Write(DamageOneShots);
            bw.Write(DamageWarning);
            bw.Write(TailBreak);
            bw.Write(MainRotorBreak);
            bw.Write(TailRotorBreak);
            bw.Write(CableDeploy);
            bw.Write(Unk77);
            bw.Write(Unk78);
            bw.Write(AltitudeWarning);
            bw.Write(DamageVolumeCurve);
            bw.Write(DamageVolumeCurve2);
            bw.Write(DamageBelow600);
            bw.Write(Unk83);
            bw.Write(Unk84);
            bw.Write(Unk85);
            bw.Write(Jet);
            bw.Write(PlayerSwitch);
            bw.Write(Unk88);

            if (Version >= 1)
            {
                bw.Write(Unk89);
                bw.Write(Unk90);
                bw.Write(StartupBroken);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Version", Version.ToString()); //CW invention, not an actual field!
            RelXml.StringTag(sb, indent, "MainRotor", RelXml.HashString(MainRotor));
            RelXml.StringTag(sb, indent, "TailRotor", RelXml.HashString(TailRotor));
            RelXml.StringTag(sb, indent, "Exhaust", RelXml.HashString(Exhaust));
            RelXml.StringTag(sb, indent, "Engine", RelXml.HashString(Engine));
            RelXml.StringTag(sb, indent, "InternalCabinTone", RelXml.HashString(InternalCabinTone));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.StringTag(sb, indent, "BankAngleVolume", RelXml.HashString(BankAngleVolume));
            RelXml.StringTag(sb, indent, "BankThrottleVolume", RelXml.HashString(BankThrottleVolume));
            RelXml.StringTag(sb, indent, "BankThrottlePitch", RelXml.HashString(BankThrottlePitch));
            RelXml.StringTag(sb, indent, "RotorThrottleVolume", RelXml.HashString(RotorThrottleVolume));
            RelXml.StringTag(sb, indent, "RotorThrottlePitch", RelXml.HashString(RotorThrottlePitch));
            RelXml.StringTag(sb, indent, "RotorThrottleGap", RelXml.HashString(RotorThrottleGap));
            RelXml.StringTag(sb, indent, "TailRotorThrottleVolume", RelXml.HashString(TailRotorThrottleVolume));
            RelXml.StringTag(sb, indent, "ExhaustThrottleVolume", RelXml.HashString(ExhaustThrottleVolume));
            RelXml.StringTag(sb, indent, "ExhaustThrottlePitch", RelXml.HashString(ExhaustThrottlePitch));
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.ValueTag(sb, indent, "Unk17", Unk17.ToString());
            RelXml.ValueTag(sb, indent, "Unk18", Unk18.ToString());
            RelXml.ValueTag(sb, indent, "Unk19", Unk19.ToString());
            RelXml.ValueTag(sb, indent, "Unk20", Unk20.ToString());
            RelXml.ValueTag(sb, indent, "Unk21", Unk21.ToString());
            RelXml.ValueTag(sb, indent, "Unk22", Unk22.ToString());
            RelXml.ValueTag(sb, indent, "Unk23", Unk23.ToString());
            RelXml.ValueTag(sb, indent, "Unk24", Unk24.ToString());
            RelXml.ValueTag(sb, indent, "Unk25", Unk25.ToString());
            RelXml.StringTag(sb, indent, "ThrottleResonance1", RelXml.HashString(ThrottleResonance1));
            RelXml.StringTag(sb, indent, "ThrottleResonance2", RelXml.HashString(ThrottleResonance2));
            RelXml.StringTag(sb, indent, "BankingResonance", RelXml.HashString(BankingResonance));
            RelXml.StringTag(sb, indent, "RotorStartupVolume", RelXml.HashString(RotorStartupVolume));
            RelXml.StringTag(sb, indent, "BladeStartupVolume", RelXml.HashString(BladeStartupVolume));
            RelXml.StringTag(sb, indent, "RotorStartupPitch", RelXml.HashString(RotorStartupPitch));
            RelXml.StringTag(sb, indent, "RearRotorStartupVolume", RelXml.HashString(RearRotorStartupVolume));
            RelXml.StringTag(sb, indent, "ExhaustStartupVolume", RelXml.HashString(ExhaustStartupVolume));
            RelXml.StringTag(sb, indent, "RotorStartupGap", RelXml.HashString(RotorStartupGap));
            RelXml.StringTag(sb, indent, "Startup", RelXml.HashString(Startup));
            RelXml.ValueTag(sb, indent, "Unk36", Unk36.ToString());
            RelXml.ValueTag(sb, indent, "Unk37", Unk37.ToString());
            RelXml.ValueTag(sb, indent, "Unk38", Unk38.ToString());
            RelXml.ValueTag(sb, indent, "Unk39", Unk39.ToString());
            RelXml.ValueTag(sb, indent, "Unk40", Unk40.ToString());
            RelXml.StringTag(sb, indent, "Unk41", RelXml.HashString(Unk41));
            RelXml.StringTag(sb, indent, "Unk42", RelXml.HashString(Unk42));
            RelXml.StringTag(sb, indent, "PoliceScannerCategory", RelXml.HashString(PoliceScannerCategory));
            RelXml.StringTag(sb, indent, "PoliceScannerParams", RelXml.HashString(PoliceScannerParams));
            RelXml.ValueTag(sb, indent, "RadioFlags", RadioFlags.ToString());
            RelXml.StringTag(sb, indent, "DoorOpen", RelXml.HashString(DoorOpen));
            RelXml.StringTag(sb, indent, "DoorClose", RelXml.HashString(DoorClose));
            RelXml.StringTag(sb, indent, "DoorLimit", RelXml.HashString(DoorLimit));
            RelXml.StringTag(sb, indent, "Damage", RelXml.HashString(Damage));
            RelXml.StringTag(sb, indent, "Unk50", RelXml.HashString(Unk50));
            RelXml.ValueTag(sb, indent, "Unk51", Unk51.ToString());
            RelXml.StringTag(sb, indent, "Unk52", RelXml.HashString(Unk52));
            RelXml.StringTag(sb, indent, "Unk53", RelXml.HashString(Unk53));
            RelXml.StringTag(sb, indent, "Unk54", RelXml.HashString(Unk54));
            RelXml.StringTag(sb, indent, "Unk55", RelXml.HashString(Unk55));
            RelXml.StringTag(sb, indent, "Unk56", RelXml.HashString(Unk56));
            RelXml.StringTag(sb, indent, "Unk57", RelXml.HashString(Unk57));
            RelXml.StringTag(sb, indent, "RotorBass", RelXml.HashString(RotorBass));
            RelXml.StringTag(sb, indent, "Unk59", RelXml.HashString(Unk59));
            RelXml.StringTag(sb, indent, "Collision", RelXml.HashString(Collision));
            RelXml.StringTag(sb, indent, "Fire", RelXml.HashString(Fire));
            RelXml.StringTag(sb, indent, "Distant", RelXml.HashString(Distant));
            RelXml.StringTag(sb, indent, "Unk63", RelXml.HashString(Unk63));
            RelXml.StringTag(sb, indent, "Unk64", RelXml.HashString(Unk64));
            RelXml.StringTag(sb, indent, "Unk65", RelXml.HashString(Unk65));
            RelXml.StringTag(sb, indent, "Unk66", RelXml.HashString(Unk66));
            RelXml.StringTag(sb, indent, "SuspensionUp", RelXml.HashString(SuspensionUp));
            RelXml.StringTag(sb, indent, "SuspensionDown", RelXml.HashString(SuspensionDown));
            RelXml.ValueTag(sb, indent, "Unk69", FloatUtil.ToString(Unk69));
            RelXml.ValueTag(sb, indent, "Unk70", FloatUtil.ToString(Unk70));
            RelXml.StringTag(sb, indent, "DamageOneShots", RelXml.HashString(DamageOneShots));
            RelXml.StringTag(sb, indent, "DamageWarning", RelXml.HashString(DamageWarning));
            RelXml.StringTag(sb, indent, "TailBreak", RelXml.HashString(TailBreak));
            RelXml.StringTag(sb, indent, "MainRotorBreak", RelXml.HashString(MainRotorBreak));
            RelXml.StringTag(sb, indent, "TailRotorBreak", RelXml.HashString(TailRotorBreak));
            RelXml.StringTag(sb, indent, "CableDeploy", RelXml.HashString(CableDeploy));
            RelXml.StringTag(sb, indent, "Unk77", RelXml.HashString(Unk77));
            RelXml.StringTag(sb, indent, "Unk78", RelXml.HashString(Unk78));
            RelXml.StringTag(sb, indent, "AltitudeWarning", RelXml.HashString(AltitudeWarning));
            RelXml.StringTag(sb, indent, "DamageVolumeCurve", RelXml.HashString(DamageVolumeCurve));
            RelXml.StringTag(sb, indent, "DamageVolumeCurve2", RelXml.HashString(DamageVolumeCurve2));
            RelXml.StringTag(sb, indent, "DamageBelow600", RelXml.HashString(DamageBelow600));
            RelXml.ValueTag(sb, indent, "Unk83", FloatUtil.ToString(Unk83));
            RelXml.ValueTag(sb, indent, "Unk84", FloatUtil.ToString(Unk84));
            RelXml.ValueTag(sb, indent, "Unk85", FloatUtil.ToString(Unk85));
            RelXml.StringTag(sb, indent, "Jet", RelXml.HashString(Jet));
            RelXml.StringTag(sb, indent, "PlayerSwitch", RelXml.HashString(PlayerSwitch));
            RelXml.StringTag(sb, indent, "Unk88", RelXml.HashString(Unk88));

            if (Version >= 1)
            {
                RelXml.StringTag(sb, indent, "Unk89", RelXml.HashString(Unk89));
                RelXml.StringTag(sb, indent, "Unk90", RelXml.HashString(Unk90));
                RelXml.StringTag(sb, indent, "StartupBroken", RelXml.HashString(StartupBroken));
            }

        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Version = Xml.GetChildIntAttribute(node, "Version", "value");
            MainRotor = XmlRel.GetHash(Xml.GetChildInnerText(node, "MainRotor"));
            TailRotor = XmlRel.GetHash(Xml.GetChildInnerText(node, "TailRotor"));
            Exhaust = XmlRel.GetHash(Xml.GetChildInnerText(node, "Exhaust"));
            Engine = XmlRel.GetHash(Xml.GetChildInnerText(node, "Engine"));
            InternalCabinTone = XmlRel.GetHash(Xml.GetChildInnerText(node, "InternalCabinTone"));
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            BankAngleVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "BankAngleVolume"));
            BankThrottleVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "BankThrottleVolume"));
            BankThrottlePitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "BankThrottlePitch"));
            RotorThrottleVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "RotorThrottleVolume"));
            RotorThrottlePitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "RotorThrottlePitch"));
            RotorThrottleGap = XmlRel.GetHash(Xml.GetChildInnerText(node, "RotorThrottleGap"));
            TailRotorThrottleVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "TailRotorThrottleVolume"));
            ExhaustThrottleVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustThrottleVolume"));
            ExhaustThrottlePitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustThrottlePitch"));
            Unk16 = (short)Xml.GetChildIntAttribute(node, "Unk16", "value");
            Unk17 = (short)Xml.GetChildIntAttribute(node, "Unk17", "value");
            Unk18 = (short)Xml.GetChildIntAttribute(node, "Unk18", "value");
            Unk19 = (short)Xml.GetChildIntAttribute(node, "Unk19", "value");
            Unk20 = (short)Xml.GetChildIntAttribute(node, "Unk20", "value");
            Unk21 = (short)Xml.GetChildIntAttribute(node, "Unk21", "value");
            Unk22 = (short)Xml.GetChildIntAttribute(node, "Unk22", "value");
            Unk23 = (short)Xml.GetChildIntAttribute(node, "Unk23", "value");
            Unk24 = (short)Xml.GetChildIntAttribute(node, "Unk24", "value");
            Unk25 = (short)Xml.GetChildIntAttribute(node, "Unk25", "value");
            ThrottleResonance1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ThrottleResonance1"));
            ThrottleResonance2 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ThrottleResonance2"));
            BankingResonance = XmlRel.GetHash(Xml.GetChildInnerText(node, "BankingResonance"));
            RotorStartupVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "RotorStartupVolume"));
            BladeStartupVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "BladeStartupVolume"));
            RotorStartupPitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "RotorStartupPitch"));
            RearRotorStartupVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "RearRotorStartupVolume"));
            ExhaustStartupVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "ExhaustStartupVolume"));
            RotorStartupGap = XmlRel.GetHash(Xml.GetChildInnerText(node, "RotorStartupGap"));
            Startup = XmlRel.GetHash(Xml.GetChildInnerText(node, "Startup"));
            Unk36 = (short)Xml.GetChildIntAttribute(node, "Unk36", "value");
            Unk37 = (short)Xml.GetChildIntAttribute(node, "Unk37", "value");
            Unk38 = (short)Xml.GetChildIntAttribute(node, "Unk38", "value");
            Unk39 = (short)Xml.GetChildIntAttribute(node, "Unk39", "value");
            Unk40 = Xml.GetChildIntAttribute(node, "Unk40", "value");
            Unk41 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk41"));
            Unk42 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk42"));
            PoliceScannerCategory = XmlRel.GetHash(Xml.GetChildInnerText(node, "PoliceScannerCategory"));
            PoliceScannerParams = XmlRel.GetHash(Xml.GetChildInnerText(node, "PoliceScannerParams"));
            RadioFlags = Xml.GetChildIntAttribute(node, "RadioFlags", "value");
            DoorOpen = XmlRel.GetHash(Xml.GetChildInnerText(node, "DoorOpen"));
            DoorClose = XmlRel.GetHash(Xml.GetChildInnerText(node, "DoorClose"));
            DoorLimit = XmlRel.GetHash(Xml.GetChildInnerText(node, "DoorLimit"));
            Damage = XmlRel.GetHash(Xml.GetChildInnerText(node, "Damage"));
            Unk50 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk50"));
            Unk51 = Xml.GetChildIntAttribute(node, "Unk51", "value");
            Unk52 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk52"));
            Unk53 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk53"));
            Unk54 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk54"));
            Unk55 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk55"));
            Unk56 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk56"));
            Unk57 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk57"));
            RotorBass = XmlRel.GetHash(Xml.GetChildInnerText(node, "RotorBass"));
            Unk59 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk59"));
            Collision = XmlRel.GetHash(Xml.GetChildInnerText(node, "Collision"));
            Fire = XmlRel.GetHash(Xml.GetChildInnerText(node, "Fire"));
            Distant = XmlRel.GetHash(Xml.GetChildInnerText(node, "Distant"));
            Unk63 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk63"));
            Unk64 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk64"));
            Unk65 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk65"));
            Unk66 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk66"));
            SuspensionUp = XmlRel.GetHash(Xml.GetChildInnerText(node, "SuspensionUp"));
            SuspensionDown = XmlRel.GetHash(Xml.GetChildInnerText(node, "SuspensionDown"));
            Unk69 = Xml.GetChildFloatAttribute(node, "Unk69", "value");
            Unk70 = Xml.GetChildFloatAttribute(node, "Unk70", "value");
            DamageOneShots = XmlRel.GetHash(Xml.GetChildInnerText(node, "DamageOneShots"));
            DamageWarning = XmlRel.GetHash(Xml.GetChildInnerText(node, "DamageWarning"));
            TailBreak = XmlRel.GetHash(Xml.GetChildInnerText(node, "TailBreak"));
            MainRotorBreak = XmlRel.GetHash(Xml.GetChildInnerText(node, "MainRotorBreak"));
            TailRotorBreak = XmlRel.GetHash(Xml.GetChildInnerText(node, "TailRotorBreak"));
            CableDeploy = XmlRel.GetHash(Xml.GetChildInnerText(node, "CableDeploy"));
            Unk77 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk77"));
            Unk78 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk78"));
            AltitudeWarning = XmlRel.GetHash(Xml.GetChildInnerText(node, "AltitudeWarning"));
            DamageVolumeCurve = XmlRel.GetHash(Xml.GetChildInnerText(node, "DamageVolumeCurve"));
            DamageVolumeCurve2 = XmlRel.GetHash(Xml.GetChildInnerText(node, "DamageVolumeCurve2"));
            DamageBelow600 = XmlRel.GetHash(Xml.GetChildInnerText(node, "DamageBelow600"));
            Unk83 = Xml.GetChildFloatAttribute(node, "Unk83", "value");
            Unk84 = Xml.GetChildFloatAttribute(node, "Unk84", "value");
            Unk85 = Xml.GetChildFloatAttribute(node, "Unk85", "value");
            Jet = XmlRel.GetHash(Xml.GetChildInnerText(node, "Jet"));
            PlayerSwitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "PlayerSwitch"));
            Unk88 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk88"));

            if (Version >= 1)
            {
                Unk89 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk89"));
                Unk90 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk90"));
                StartupBroken = XmlRel.GetHash(Xml.GetChildInnerText(node, "StartupBroken"));
            }
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { BankAngleVolume, BankThrottleVolume, BankThrottlePitch, RotorThrottleVolume, RotorThrottlePitch, RotorThrottleGap,
                TailRotorThrottleVolume, ExhaustThrottleVolume, ExhaustThrottlePitch, ThrottleResonance1, ThrottleResonance2, BankingResonance,
                RotorStartupVolume, BladeStartupVolume, RotorStartupPitch, RearRotorStartupVolume, ExhaustStartupVolume, RotorStartupGap,
                Unk50, Unk59, DamageVolumeCurve, DamageVolumeCurve2 };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { MainRotor, TailRotor, Exhaust, Engine, InternalCabinTone, Startup, Unk41, Unk42, PoliceScannerCategory,
                DoorOpen, DoorClose, DoorLimit, Damage, Unk56, Unk57, RotorBass, Fire, Distant, Unk63, Unk64, Unk65, Unk66, 
                SuspensionUp, SuspensionDown, DamageOneShots, DamageWarning, TailBreak, MainRotorBreak, TailRotorBreak, CableDeploy,
                Unk77, Unk78, AltitudeWarning, DamageBelow600, Jet, PlayerSwitch, Unk88, Unk89, Unk90, StartupBroken };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { PoliceScannerParams, Collision };
        }
    }
    [TC(typeof(EXP))] public class Dat151VehicleTrailer : Dat151RelData
    {
        public MetaHash Suspension { get; set; }
        public int Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }
        public MetaHash Mods { get; set; }
        public MetaHash Fire { get; set; }
        public MetaHash Unk06 { get; set; }//0
        public float Unk07 { get; set; }
        public int Unk08 { get; set; }
        public float Unk09 { get; set; }
        public int Unk10 { get; set; }
        public MetaHash Unk11 { get; set; }//0
        public float Unk12 { get; set; }

        public Dat151VehicleTrailer(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.VehicleTrailer;
            TypeID = (byte)Type;
        }
        public Dat151VehicleTrailer(RelData d, BinaryReader br) : base(d, br)
        {
            Suspension = br.ReadUInt32();
            Unk02 = br.ReadInt32();
            Unk03 = br.ReadUInt32();
            Mods = br.ReadUInt32();
            Fire = br.ReadUInt32();
            Unk06 = br.ReadUInt32();//0
            Unk07 = br.ReadSingle();
            Unk08 = br.ReadInt32();
            Unk09 = br.ReadSingle();
            Unk10 = br.ReadInt32();
            Unk11 = br.ReadUInt32();//0
            Unk12 = br.ReadSingle();

            if (Unk06 != 0)
            { }
            if (Unk11 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Suspension);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Mods);
            bw.Write(Fire);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Suspension", RelXml.HashString(Suspension));
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.StringTag(sb, indent, "Mods", RelXml.HashString(Mods));
            RelXml.StringTag(sb, indent, "Fire", RelXml.HashString(Fire));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", FloatUtil.ToString(Unk07));
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", FloatUtil.ToString(Unk09));
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.StringTag(sb, indent, "Unk11", RelXml.HashString(Unk11));
            RelXml.ValueTag(sb, indent, "Unk12", FloatUtil.ToString(Unk12));
        }
        public override void ReadXml(XmlNode node)
        {
            Suspension = XmlRel.GetHash(Xml.GetChildInnerText(node, "Suspension"));
            Unk02 = Xml.GetChildIntAttribute(node, "Unk02", "value");
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Mods = XmlRel.GetHash(Xml.GetChildInnerText(node, "Mods"));
            Fire = XmlRel.GetHash(Xml.GetChildInnerText(node, "Fire"));
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = Xml.GetChildFloatAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildIntAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildFloatAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildIntAttribute(node, "Unk10", "value");
            Unk11 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk11"));
            Unk12 = Xml.GetChildFloatAttribute(node, "Unk12", "value");
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Suspension, Unk03, Fire  };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { Mods };
        }
    }
    [TC(typeof(EXP))] public class Dat151Train : Dat151RelData
    {
        public MetaHash Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }//0
        public MetaHash Unk03 { get; set; }
        public MetaHash Unk04 { get; set; }
        public MetaHash BigBrakeRelease { get; set; }
        public MetaHash BrakeRelease { get; set; }
        public MetaHash Unk07 { get; set; }
        public MetaHash Horn { get; set; }
        public MetaHash Unk09 { get; set; }
        public MetaHash Unk10 { get; set; }
        public MetaHash Carriage { get; set; }
        public MetaHash Unk12 { get; set; }
        public MetaHash Unk13 { get; set; }
        public MetaHash Unk14 { get; set; }
        public MetaHash CarriagePitch { get; set; }
        public MetaHash CarriageVolume { get; set; }
        public MetaHash DriveTonePitch { get; set; }
        public MetaHash DriveToneVolume { get; set; }
        public MetaHash DriveToneSynthPitch { get; set; }
        public MetaHash DriveToneSynthVolume { get; set; }
        public MetaHash GrindPitch { get; set; }
        public MetaHash GrindVolume { get; set; }
        public MetaHash IdlePitch { get; set; }
        public MetaHash IdleVolume { get; set; }
        public MetaHash SquealPitch { get; set; }
        public MetaHash SquealVolume { get; set; }
        public MetaHash ScrapeSpeedVolume { get; set; }
        public MetaHash WheelVolume { get; set; }
        public MetaHash WheelDelay { get; set; }
        public MetaHash RumbleVolume { get; set; }
        public MetaHash BrakeVelocityPitch { get; set; }
        public MetaHash BrakeVelocityVolume { get; set; }
        public MetaHash BrakeAccelerationPitch { get; set; }
        public MetaHash BrakeAccelerationVolume { get; set; }
        public MetaHash Unk35 { get; set; }
        public MetaHash Unk36 { get; set; }
        public MetaHash Unk37 { get; set; }//constant_one
        public MetaHash Collision { get; set; }


        public Dat151Train(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Train;
            TypeID = (byte)Type;
        }
        public Dat151Train(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadUInt32();
            Unk03 = br.ReadUInt32();
            Unk04 = br.ReadUInt32();
            BigBrakeRelease = br.ReadUInt32();
            BrakeRelease = br.ReadUInt32();
            Unk07 = br.ReadUInt32();
            Horn = br.ReadUInt32();
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadUInt32();
            Carriage = br.ReadUInt32();
            Unk12 = br.ReadUInt32();
            Unk13 = br.ReadUInt32();
            Unk14 = br.ReadUInt32();
            CarriagePitch = br.ReadUInt32();
            CarriageVolume = br.ReadUInt32();
            DriveTonePitch = br.ReadUInt32();
            DriveToneVolume = br.ReadUInt32();
            DriveToneSynthPitch = br.ReadUInt32();
            DriveToneSynthVolume = br.ReadUInt32();
            GrindPitch = br.ReadUInt32();
            GrindVolume = br.ReadUInt32();
            IdlePitch = br.ReadUInt32();
            IdleVolume = br.ReadUInt32();
            SquealPitch = br.ReadUInt32();
            SquealVolume = br.ReadUInt32();
            ScrapeSpeedVolume = br.ReadUInt32();
            WheelVolume = br.ReadUInt32();
            WheelDelay = br.ReadUInt32();
            RumbleVolume = br.ReadUInt32();
            BrakeVelocityPitch = br.ReadUInt32();
            BrakeVelocityVolume = br.ReadUInt32();
            BrakeAccelerationPitch = br.ReadUInt32();
            BrakeAccelerationVolume = br.ReadUInt32();
            Unk35 = br.ReadUInt32();
            Unk36 = br.ReadUInt32();
            Unk37 = br.ReadUInt32();
            Collision = br.ReadUInt32();

            if (Unk02 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(BigBrakeRelease);
            bw.Write(BrakeRelease);
            bw.Write(Unk07);
            bw.Write(Horn);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Carriage);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(CarriagePitch);
            bw.Write(CarriageVolume);
            bw.Write(DriveTonePitch);
            bw.Write(DriveToneVolume);
            bw.Write(DriveToneSynthPitch);
            bw.Write(DriveToneSynthVolume);
            bw.Write(GrindPitch);
            bw.Write(GrindVolume);
            bw.Write(IdlePitch);
            bw.Write(IdleVolume);
            bw.Write(SquealPitch);
            bw.Write(SquealVolume);
            bw.Write(ScrapeSpeedVolume);
            bw.Write(WheelVolume);
            bw.Write(WheelDelay);
            bw.Write(RumbleVolume);
            bw.Write(BrakeVelocityPitch);
            bw.Write(BrakeVelocityVolume);
            bw.Write(BrakeAccelerationPitch);
            bw.Write(BrakeAccelerationVolume);
            bw.Write(Unk35);
            bw.Write(Unk36);
            bw.Write(Unk37);
            bw.Write(Collision);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
            RelXml.StringTag(sb, indent, "BigBrakeRelease", RelXml.HashString(BigBrakeRelease));
            RelXml.StringTag(sb, indent, "BrakeRelease", RelXml.HashString(BrakeRelease));
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.StringTag(sb, indent, "Horn", RelXml.HashString(Horn));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
            RelXml.StringTag(sb, indent, "Carriage", RelXml.HashString(Carriage));
            RelXml.StringTag(sb, indent, "Unk12", RelXml.HashString(Unk12));
            RelXml.StringTag(sb, indent, "Unk13", RelXml.HashString(Unk13));
            RelXml.StringTag(sb, indent, "Unk14", RelXml.HashString(Unk14));
            RelXml.StringTag(sb, indent, "CarriagePitch", RelXml.HashString(CarriagePitch));
            RelXml.StringTag(sb, indent, "CarriageVolume", RelXml.HashString(CarriageVolume));
            RelXml.StringTag(sb, indent, "DriveTonePitch", RelXml.HashString(DriveTonePitch));
            RelXml.StringTag(sb, indent, "DriveToneVolume", RelXml.HashString(DriveToneVolume));
            RelXml.StringTag(sb, indent, "DriveToneSynthPitch", RelXml.HashString(DriveToneSynthPitch));
            RelXml.StringTag(sb, indent, "DriveToneSynthVolume", RelXml.HashString(DriveToneSynthVolume));
            RelXml.StringTag(sb, indent, "GrindPitch", RelXml.HashString(GrindPitch));
            RelXml.StringTag(sb, indent, "GrindVolume", RelXml.HashString(GrindVolume));
            RelXml.StringTag(sb, indent, "IdlePitch", RelXml.HashString(IdlePitch));
            RelXml.StringTag(sb, indent, "IdleVolume", RelXml.HashString(IdleVolume));
            RelXml.StringTag(sb, indent, "SquealPitch", RelXml.HashString(SquealPitch));
            RelXml.StringTag(sb, indent, "SquealVolume", RelXml.HashString(SquealVolume));
            RelXml.StringTag(sb, indent, "ScrapeSpeedVolume", RelXml.HashString(ScrapeSpeedVolume));
            RelXml.StringTag(sb, indent, "WheelVolume", RelXml.HashString(WheelVolume));
            RelXml.StringTag(sb, indent, "WheelDelay", RelXml.HashString(WheelDelay));
            RelXml.StringTag(sb, indent, "RumbleVolume", RelXml.HashString(RumbleVolume));
            RelXml.StringTag(sb, indent, "BrakeVelocityPitch", RelXml.HashString(BrakeVelocityPitch));
            RelXml.StringTag(sb, indent, "BrakeVelocityVolume", RelXml.HashString(BrakeVelocityVolume));
            RelXml.StringTag(sb, indent, "BrakeAccelerationPitch", RelXml.HashString(BrakeAccelerationPitch));
            RelXml.StringTag(sb, indent, "BrakeAccelerationVolume", RelXml.HashString(BrakeAccelerationVolume));
            RelXml.StringTag(sb, indent, "Unk35", RelXml.HashString(Unk35));
            RelXml.StringTag(sb, indent, "Unk36", RelXml.HashString(Unk36));
            RelXml.StringTag(sb, indent, "Unk37", RelXml.HashString(Unk37));
            RelXml.StringTag(sb, indent, "Collision", RelXml.HashString(Collision));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
            BigBrakeRelease = XmlRel.GetHash(Xml.GetChildInnerText(node, "BigBrakeRelease"));
            BrakeRelease = XmlRel.GetHash(Xml.GetChildInnerText(node, "BrakeRelease"));
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Horn = XmlRel.GetHash(Xml.GetChildInnerText(node, "Horn"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
            Carriage = XmlRel.GetHash(Xml.GetChildInnerText(node, "Carriage"));
            Unk12 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk12"));
            Unk13 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk13"));
            Unk14 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk14"));
            CarriagePitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "CarriagePitch"));
            CarriageVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "CarriageVolume"));
            DriveTonePitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "DriveTonePitch"));
            DriveToneVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "DriveToneVolume"));
            DriveToneSynthPitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "DriveToneSynthPitch"));
            DriveToneSynthVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "DriveToneSynthVolume"));
            GrindPitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "GrindPitch"));
            GrindVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "GrindVolume"));
            IdlePitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "IdlePitch"));
            IdleVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "IdleVolume"));
            SquealPitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "SquealPitch"));
            SquealVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "SquealVolume"));
            ScrapeSpeedVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "ScrapeSpeedVolume"));
            WheelVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "WheelVolume"));
            WheelDelay = XmlRel.GetHash(Xml.GetChildInnerText(node, "WheelDelay"));
            RumbleVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "RumbleVolume"));
            BrakeVelocityPitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "BrakeVelocityPitch"));
            BrakeVelocityVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "BrakeVelocityVolume"));
            BrakeAccelerationPitch = XmlRel.GetHash(Xml.GetChildInnerText(node, "BrakeAccelerationPitch"));
            BrakeAccelerationVolume = XmlRel.GetHash(Xml.GetChildInnerText(node, "BrakeAccelerationVolume"));
            Unk35 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk35"));
            Unk36 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk36"));
            Unk37 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk37"));
            Collision = XmlRel.GetHash(Xml.GetChildInnerText(node, "Collision"));
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { CarriagePitch, CarriageVolume, DriveTonePitch, DriveToneVolume, DriveToneSynthPitch, DriveToneSynthVolume,
                GrindPitch, GrindVolume, IdlePitch, IdleVolume, SquealPitch, SquealVolume, ScrapeSpeedVolume, WheelVolume, WheelDelay,
                RumbleVolume, BrakeVelocityPitch, BrakeVelocityVolume, BrakeAccelerationPitch, BrakeAccelerationVolume, Unk36, Unk37 };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk01, Unk03, Unk04, BigBrakeRelease, BrakeRelease, Unk07, Horn, Unk09, Unk10, Carriage, Unk12, Unk13, Unk14, Unk35 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { Collision };
        }
    }
    [TC(typeof(EXP))] public class Dat151AnimalParamsItem : IMetaXmlItem
    {
        public string Name { get; set; }
        public float Unk1 { get; set; }
        public float Unk2 { get; set; }
        public int Unk3 { get; set; }
        public float Unk4 { get; set; }
        public int Unk5 { get; set; }
        public int Unk6 { get; set; }
        public float Unk7 { get; set; }
        public byte Unk8 { get; set; }

        public override string ToString()
        {
            return Name;
        }

        public Dat151AnimalParamsItem()
        {
        }
        public Dat151AnimalParamsItem(BinaryReader br)
        {
            var data = br.ReadBytes(32);
            Name = Encoding.ASCII.GetString(data).Replace("\0", "");
            Unk1 = br.ReadSingle();
            Unk2 = br.ReadSingle();
            Unk3 = br.ReadInt32();
            Unk4 = br.ReadSingle();
            Unk5 = br.ReadInt32();
            Unk6 = br.ReadInt32();
            Unk7 = br.ReadSingle();
            Unk8 = br.ReadByte();
        }
        public void Write(BinaryWriter bw)
        {
            var data = new byte[32];
            int len = Math.Min(Name?.Length ?? 0, 32);
            if (len > 0)
            {
                Encoding.ASCII.GetBytes(Name, 0, len, data, 0);
            }
            bw.Write(data);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(Unk3);
            bw.Write(Unk4);
            bw.Write(Unk5);
            bw.Write(Unk6);
            bw.Write(Unk7);
            bw.Write(Unk8);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Name", Name);
            RelXml.ValueTag(sb, indent, "Unk1", FloatUtil.ToString(Unk1));
            RelXml.ValueTag(sb, indent, "Unk2", FloatUtil.ToString(Unk2));
            RelXml.ValueTag(sb, indent, "Unk3", Unk3.ToString());
            RelXml.ValueTag(sb, indent, "Unk4", FloatUtil.ToString(Unk4));
            RelXml.ValueTag(sb, indent, "Unk5", Unk5.ToString());
            RelXml.ValueTag(sb, indent, "Unk6", Unk6.ToString());
            RelXml.ValueTag(sb, indent, "Unk7", FloatUtil.ToString(Unk7));
            RelXml.ValueTag(sb, indent, "Unk8", Unk8.ToString());
        }
        public void ReadXml(XmlNode node)
        {
            Name = Xml.GetChildInnerText(node, "Name");
            Unk1 = Xml.GetChildFloatAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildFloatAttribute(node, "Unk2", "value");
            Unk3 = Xml.GetChildIntAttribute(node, "Unk3", "value");
            Unk4 = Xml.GetChildFloatAttribute(node, "Unk4", "value");
            Unk5 = Xml.GetChildIntAttribute(node, "Unk5", "value");
            Unk6 = Xml.GetChildIntAttribute(node, "Unk6", "value");
            Unk7 = Xml.GetChildFloatAttribute(node, "Unk7", "value");
            Unk8 = (byte)Xml.GetChildUIntAttribute(node, "Unk8", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151AnimalParams : Dat151RelData
    {
        public int Unk01 { get; set; }
        public float Unk02 { get; set; }
        public float Unk03 { get; set; }
        public int Unk04 { get; set; }
        public byte Unk05 { get; set; }
        public MetaHash Unk06 { get; set; }
        public MetaHash Unk07 { get; set; }
        public MetaHash Unk08 { get; set; }
        public float Unk09 { get; set; }
        public MetaHash Unk10 { get; set; }
        public byte ItemCount { get; set; }
        public Dat151AnimalParamsItem[] Items { get; set; }

        public Dat151AnimalParams(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.AnimalParams;
            TypeID = (byte)Type;
        }
        public Dat151AnimalParams(RelData d, BinaryReader br) : base(d, br)
        {

            Unk01 = br.ReadInt32();
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadInt32();
            Unk05 = br.ReadByte();
            Unk06 = br.ReadUInt32();
            Unk07 = br.ReadUInt32();
            Unk08 = br.ReadUInt32();
            Unk09 = br.ReadSingle();
            Unk10 = br.ReadUInt32();
            ItemCount = br.ReadByte();

            var items = new Dat151AnimalParamsItem[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                items[i] = new Dat151AnimalParamsItem(br);
            }
            Items = items;

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }

        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.ValueTag(sb, indent, "Unk09", FloatUtil.ToString(Unk09));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildIntAttribute(node, "Unk04", "value");
            Unk05 = (byte)Xml.GetChildUIntAttribute(node, "Unk05", "value");
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = Xml.GetChildFloatAttribute(node, "Unk09", "value");
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
            Items = XmlRel.ReadItemArray<Dat151AnimalParamsItem>(node, "Items");
            ItemCount = (byte)(Items?.Length ?? 0);
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { Unk06, Unk07 };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk08, Unk10 };
        }
    }
    [TC(typeof(EXP))] public class Dat151SpeechParams : Dat151RelData
    {
        public FlagsUint Flags { get; set; } //0xAAA50405
        public int Unk01 { get; set; } //3
        public int Unk02 { get; set; } //30000
        public byte Unk03 { get; set; } //0x00000202
        public byte Unk04 { get; set; }
        public short Unk05 { get; set; } //0
        public MetaHash Unk06 { get; set; } //0
        public int Unk07 { get; set; } //0xFFFFFFFF


        public Dat151SpeechParams(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.SpeechParams;
            TypeID = (byte)Type;
        }
        public Dat151SpeechParams(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Unk01 = br.ReadInt32();
            Unk02 = br.ReadInt32();
            Unk03 = br.ReadByte();
            Unk04 = br.ReadByte();
            Unk05 = br.ReadInt16();
            Unk06 = br.ReadUInt32();
            Unk07 = br.ReadInt32();

            if (Unk01 > 0xFFFF)
            { }
            if (Unk02 > 0xFFFF)
            { }
            if (Unk05 != 0)
            { }
            if (Unk06 != 0)
            { }
            if (Unk07 != -1)
            { }


            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = Xml.GetChildIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildIntAttribute(node, "Unk02", "value");
            Unk03 = (byte)Xml.GetChildUIntAttribute(node, "Unk03", "value");
            Unk04 = (byte)Xml.GetChildUIntAttribute(node, "Unk04", "value");
            Unk05 = (short)Xml.GetChildIntAttribute(node, "Unk05", "value");
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = Xml.GetChildIntAttribute(node, "Unk07", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151MeleeCombat : Dat151RelData
    {
        public MetaHash Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }
        public MetaHash Unk04 { get; set; }
        public MetaHash Unk05 { get; set; }
        public MetaHash Unk06 { get; set; }
        public MetaHash Unk07 { get; set; }
        public MetaHash Unk08 { get; set; }
        public MetaHash Unk09 { get; set; }
        public MetaHash Unk10 { get; set; }
        public MetaHash Unk11 { get; set; }
        public MetaHash Unk12 { get; set; }
        public MetaHash Unk13 { get; set; }
        public MetaHash Unk14 { get; set; }
        public MetaHash Unk15 { get; set; }
        public MetaHash Unk16 { get; set; }
        public MetaHash Unk17 { get; set; }
        public MetaHash Unk18 { get; set; }

        public Dat151MeleeCombat(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.MeleeCombat;
            TypeID = (byte)Type;
        }
        public Dat151MeleeCombat(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadUInt32();
            Unk03 = br.ReadUInt32();
            Unk04 = br.ReadUInt32();
            Unk05 = br.ReadUInt32();
            Unk06 = br.ReadUInt32();
            Unk07 = br.ReadUInt32();
            Unk08 = br.ReadUInt32();
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadUInt32();
            Unk11 = br.ReadUInt32();
            Unk12 = br.ReadUInt32();
            Unk13 = br.ReadUInt32();
            Unk14 = br.ReadUInt32();
            Unk15 = br.ReadUInt32();
            Unk16 = br.ReadUInt32();
            Unk17 = br.ReadUInt32();
            Unk18 = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
            RelXml.StringTag(sb, indent, "Unk11", RelXml.HashString(Unk11));
            RelXml.StringTag(sb, indent, "Unk12", RelXml.HashString(Unk12));
            RelXml.StringTag(sb, indent, "Unk13", RelXml.HashString(Unk13));
            RelXml.StringTag(sb, indent, "Unk14", RelXml.HashString(Unk14));
            RelXml.StringTag(sb, indent, "Unk15", RelXml.HashString(Unk15));
            RelXml.StringTag(sb, indent, "Unk16", RelXml.HashString(Unk16));
            RelXml.StringTag(sb, indent, "Unk17", RelXml.HashString(Unk17));
            RelXml.StringTag(sb, indent, "Unk18", RelXml.HashString(Unk18));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
            Unk11 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk11"));
            Unk12 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk12"));
            Unk13 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk13"));
            Unk14 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk14"));
            Unk15 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk15"));
            Unk16 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk16"));
            Unk17 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk17"));
            Unk18 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk18"));
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk01, Unk02, Unk03, Unk04, Unk05, Unk06, Unk07, Unk08, Unk09, Unk10, Unk11, Unk12, Unk13, Unk14, Unk15, Unk16, Unk17, Unk18 };
        }
    }
    [TC(typeof(EXP))] public class Dat151SpeechContext : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public int Unk01 { get; set; }
        public int Unk02 { get; set; }
        public int Unk03 { get; set; }
        public int Unk04 { get; set; }
        public int Unk05 { get; set; }
        public MetaHash Unk06 { get; set; }//0
        public MetaHash Unk07 { get; set; }//0
        public MetaHash Unk08 { get; set; }//0
        public MetaHash Unk09 { get; set; }
        public int ItemCount { get; set; }
        public Dat151HashFloat[] Items { get; set; }//SpeechChoice, probability?


        public Dat151SpeechContext(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.SpeechContext;
            TypeID = (byte)Type;
        }
        public Dat151SpeechContext(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Unk01 = br.ReadInt32();
            Unk02 = br.ReadInt32();
            Unk03 = br.ReadInt32();
            Unk04 = br.ReadInt32();
            Unk05 = br.ReadInt32();
            Unk06 = br.ReadUInt32();//0
            Unk07 = br.ReadUInt32();//0
            Unk08 = br.ReadUInt32();//0
            Unk09 = br.ReadUInt32();
            ItemCount = br.ReadInt32();

            var items = new Dat151HashFloat[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                items[i] = new Dat151HashFloat(br);
            }
            Items = items;

            if (Unk06 != 0)
            { }
            if (Unk07 != 0)
            { }
            if (Unk08 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = Xml.GetChildIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildIntAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildIntAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildIntAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildIntAttribute(node, "Unk05", "value");
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Items = XmlRel.ReadItemArray<Dat151HashFloat>(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            list.Add(Unk09);
            foreach (var item in Items)
            {
                list.Add(item.Hash);
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151SpeechChoice : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public MetaHash Unk01 { get; set; }//????? must be responsible for the speech itself somehow
        public int Unk02 { get; set; }
        public int Unk03 { get; set; }
        public byte Unk04 { get; set; }
        public byte Unk05 { get; set; }
        public byte Unk06 { get; set; }//0
        public byte Unk07 { get; set; }//0
        public MetaHash Unk08 { get; set; }//0
        public MetaHash Unk09 { get; set; }//0
        public byte Unk10 { get; set; }
        public byte Unk11 { get; set; }
        public byte Unk12 { get; set; }
        public byte Unk13 { get; set; }
        public byte Unk14 { get; set; }//only when Unk11>2
        public byte Unk15 { get; set; }//only when Unk11>2
        public byte Unk16 { get; set; }//only when Unk11>2
        public byte Unk17 { get; set; }//only when Unk11>2


        public Dat151SpeechChoice(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.SpeechChoice;
            TypeID = (byte)Type;
        }
        public Dat151SpeechChoice(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadInt32();
            Unk03 = br.ReadInt32();
            Unk04 = br.ReadByte();
            Unk05 = br.ReadByte();
            Unk06 = br.ReadByte();
            Unk07 = br.ReadByte();
            Unk08 = br.ReadUInt32();//0
            Unk09 = br.ReadUInt32();//0
            Unk10 = br.ReadByte();
            Unk11 = br.ReadByte();
            Unk12 = br.ReadByte();
            Unk13 = br.ReadByte();

            if (Unk11 > 2)
            {
                Unk14 = br.ReadByte();
                Unk15 = br.ReadByte();
                Unk16 = br.ReadByte();
                Unk17 = br.ReadByte();
            }


            if (Unk05 > 3)
            { }
            if (Unk06 != 0)
            { }
            if (Unk07 != 0)
            { }
            if (Unk08 != 0)
            { }
            if (Unk09 != 0)
            { }
            if (Unk11 > 3)
            { }


            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }

        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            if (Unk11 > 2)
            {
                bw.Write(Unk14);
                bw.Write(Unk15);
                bw.Write(Unk16);
                bw.Write(Unk17);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.ValueTag(sb, indent, "Unk06", Unk06.ToString());
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.ValueTag(sb, indent, "Unk11", Unk11.ToString());
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.ToString());
            RelXml.ValueTag(sb, indent, "Unk13", Unk13.ToString());
            if (Unk11 > 2)
            {
                RelXml.ValueTag(sb, indent, "Unk14", Unk14.ToString());
                RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
                RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
                RelXml.ValueTag(sb, indent, "Unk17", Unk17.ToString());
            }
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = Xml.GetChildIntAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildIntAttribute(node, "Unk03", "value");
            Unk04 = (byte)Xml.GetChildUIntAttribute(node, "Unk04", "value");
            Unk05 = (byte)Xml.GetChildUIntAttribute(node, "Unk05", "value");
            Unk06 = (byte)Xml.GetChildUIntAttribute(node, "Unk06", "value");
            Unk07 = (byte)Xml.GetChildUIntAttribute(node, "Unk07", "value");
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = (byte)Xml.GetChildUIntAttribute(node, "Unk10", "value");
            Unk11 = (byte)Xml.GetChildUIntAttribute(node, "Unk11", "value");
            Unk12 = (byte)Xml.GetChildUIntAttribute(node, "Unk12", "value");
            Unk13 = (byte)Xml.GetChildUIntAttribute(node, "Unk13", "value");
            if (Unk11 > 2)
            {
                Unk14 = (byte)Xml.GetChildUIntAttribute(node, "Unk14", "value");
                Unk15 = (byte)Xml.GetChildUIntAttribute(node, "Unk15", "value");
                Unk16 = (byte)Xml.GetChildUIntAttribute(node, "Unk16", "value");
                Unk17 = (byte)Xml.GetChildUIntAttribute(node, "Unk17", "value");
            }
        }
    }
    [TC(typeof(EXP))] public class Dat151SpeechChoice2 : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public MetaHash Unk01 { get; set; }//????? must be something to do with speech item
        public MetaHash Unk02 { get; set; }//0
        public int Unk03 { get; set; }
        public MetaHash Unk04 { get; set; }//0
        public MetaHash Unk05 { get; set; }//0
        public MetaHash Unk06 { get; set; }//0
        public byte Unk07 { get; set; }//3
        public byte Unk08 { get; set; }//0
        public byte Unk09 { get; set; }
        public byte ItemCount { get; set; }
        public MetaHash[] Items { get; set; }//SpeechContext or SpeechChoice

        public Dat151SpeechChoice2(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.SpeechChoice2;
            TypeID = (byte)Type;
        }
        public Dat151SpeechChoice2(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadUInt32();//0
            Unk03 = br.ReadInt32();
            Unk04 = br.ReadUInt32();//0
            Unk05 = br.ReadUInt32();//0
            Unk06 = br.ReadUInt32();//0
            Unk07 = br.ReadByte();//3
            Unk08 = br.ReadByte();//0
            Unk09 = br.ReadByte();
            ItemCount = br.ReadByte();
            Items = new MetaHash[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = br.ReadUInt32();
            }

            if (Unk02 != 0)
            { }
            if (Unk04 != 0)
            { }
            if (Unk05 != 0)
            { }
            if (Unk06 != 0)
            { }
            if (Unk07 != 3)
            { }
            if (Unk08 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                bw.Write(Items[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.WriteHashItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = Xml.GetChildIntAttribute(node, "Unk03", "value");
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = (byte)Xml.GetChildUIntAttribute(node, "Unk07", "value");
            Unk08 = (byte)Xml.GetChildUIntAttribute(node, "Unk08", "value");
            Unk09 = (byte)Xml.GetChildUIntAttribute(node, "Unk09", "value");
            Items = XmlRel.ReadHashItemArray(node, "Items");
            ItemCount = (byte)(Items?.Length ?? 0);
        }
        public override MetaHash[] GetGameHashes()
        {
            return Items;
        }
    }
    [TC(typeof(EXP))] public class Dat151SpeechContextList : Dat151RelData  //dlc_btl_nightclub_scl, dlc_btl_nightclub_queue_scl
    {
        public int ItemCount { get; set; }
        public MetaHash[] Items { get; set; }

        public Dat151SpeechContextList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.SpeechContextList;
            TypeID = (byte)Type;
        }
        public Dat151SpeechContextList(RelData d, BinaryReader br) : base(d, br)
        {
            ItemCount = br.ReadInt32();
            Items = new MetaHash[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = br.ReadUInt32();
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                bw.Write(Items[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteHashItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Items = XmlRel.ReadHashItemArray(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
        public override MetaHash[] GetGameHashes()
        {
            return Items;
        }
    }
    [TC(typeof(EXP))] public class Dat151Shoe : Dat151RelData //shoe type
    {
        public MetaHash Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }
        public MetaHash Unk04 { get; set; }
        public MetaHash Unk05 { get; set; }
        public MetaHash Unk06 { get; set; }
        public MetaHash Unk07 { get; set; }
        public MetaHash Unk08 { get; set; }
        public MetaHash Unk09 { get; set; }
        public MetaHash Unk10 { get; set; }
        public MetaHash Unk11 { get; set; }
        public MetaHash Unk12 { get; set; }
        public MetaHash Unk13 { get; set; }
        public float Unk14 { get; set; }
        public float Unk15 { get; set; }
        public int Unk16 { get; set; }
        public float Unk17 { get; set; }
        public MetaHash Unk18 { get; set; }
        public MetaHash Unk19 { get; set; }
        public MetaHash Unk20 { get; set; }


        public Dat151Shoe(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Shoe;
            TypeID = (byte)Type;
        }
        public Dat151Shoe(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadUInt32();
            Unk03 = br.ReadUInt32();
            Unk04 = br.ReadUInt32();
            Unk05 = br.ReadUInt32();
            Unk06 = br.ReadUInt32();
            Unk07 = br.ReadUInt32();
            Unk08 = br.ReadUInt32();
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadUInt32();
            Unk11 = br.ReadUInt32();
            Unk12 = br.ReadUInt32();
            Unk13 = br.ReadUInt32();
            Unk14 = br.ReadSingle();
            Unk15 = br.ReadSingle();
            Unk16 = br.ReadInt32();
            Unk17 = br.ReadSingle();
            Unk18 = br.ReadUInt32();
            Unk19 = br.ReadUInt32();
            Unk20 = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
            bw.Write(Unk19);
            bw.Write(Unk20);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
            RelXml.StringTag(sb, indent, "Unk11", RelXml.HashString(Unk11));
            RelXml.StringTag(sb, indent, "Unk12", RelXml.HashString(Unk12));
            RelXml.StringTag(sb, indent, "Unk13", RelXml.HashString(Unk13));
            RelXml.ValueTag(sb, indent, "Unk14", FloatUtil.ToString(Unk14));
            RelXml.ValueTag(sb, indent, "Unk15", FloatUtil.ToString(Unk15));
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.ValueTag(sb, indent, "Unk17", FloatUtil.ToString(Unk17));
            RelXml.StringTag(sb, indent, "Unk18", RelXml.HashString(Unk18));
            RelXml.StringTag(sb, indent, "Unk19", RelXml.HashString(Unk19));
            RelXml.StringTag(sb, indent, "Unk20", RelXml.HashString(Unk20));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
            Unk11 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk11"));
            Unk12 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk12"));
            Unk13 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk13"));
            Unk14 = Xml.GetChildFloatAttribute(node, "Unk14", "value");
            Unk15 = Xml.GetChildFloatAttribute(node, "Unk15", "value");
            Unk16 = Xml.GetChildIntAttribute(node, "Unk16", "value");
            Unk17 = Xml.GetChildFloatAttribute(node, "Unk17", "value");
            Unk18 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk18"));
            Unk19 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk19"));
            Unk20 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk20"));
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk01, Unk02, Unk03, Unk04, Unk05, Unk06, Unk07, Unk08, Unk09, Unk10, Unk11, Unk12, Unk13, Unk18, Unk19, Unk20 };
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk22Item : IMetaXmlItem
    {
        public MetaHash Unk01 { get; set; }//state name? eg. stop,walk,run,sprint,jump,stairs_stop,stairs_walk,stairs_run,slopes,slopes_run,ladder,vault
        public float Unk02 { get; set; }
        public float Unk03 { get; set; }
        public float Unk04 { get; set; }
        public float Unk05 { get; set; }
        public float Unk06 { get; set; }
        public float Unk07 { get; set; }
        public float Unk08 { get; set; }
        public int Unk09 { get; set; }

        public Dat151Unk22Item()
        { }
        public Dat151Unk22Item(BinaryReader br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadSingle();
            Unk07 = br.ReadSingle();
            Unk08 = br.ReadSingle();
            Unk09 = br.ReadInt32();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", FloatUtil.ToString(Unk07));
            RelXml.ValueTag(sb, indent, "Unk08", FloatUtil.ToString(Unk08));
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
        }
        public void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildFloatAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildFloatAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildIntAttribute(node, "Unk09", "value");
        }
        public override string ToString()
        {
            return Unk01.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk22 : Dat151RelData  //player/creature?
    {
        public int Unk01 { get; set; }
        public int Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }
        public float Unk04 { get; set; }
        public float Unk05 { get; set; }
        public float Unk06 { get; set; }
        public int ItemCount { get; set; }
        public Dat151Unk22Item[] Items { get; set; }


        public Dat151Unk22(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk22;
            TypeID = (byte)Type;
        }
        public Dat151Unk22(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadInt32();
            Unk02 = br.ReadInt32();
            Unk03 = br.ReadUInt32();
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadSingle();
            ItemCount = br.ReadInt32();
            Items = new Dat151Unk22Item[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151Unk22Item(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildIntAttribute(node, "Unk02", "value");
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Items = XmlRel.ReadItemArray<Dat151Unk22Item>(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { Unk03 };
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk23 : Dat151RelData
    {
        public MetaHash Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }//0
        public float Unk03 { get; set; }
        public MetaHash Unk04 { get; set; }
        public MetaHash Unk05 { get; set; }//0
        public float Unk06 { get; set; }
        public MetaHash Unk07 { get; set; }
        public MetaHash Unk08 { get; set; }//0
        public float Unk09 { get; set; }


        public Dat151Unk23(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk23;
            TypeID = (byte)Type;
        }
        public Dat151Unk23(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadUInt32();//0
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadUInt32();
            Unk05 = br.ReadUInt32();//0
            Unk06 = br.ReadSingle();
            Unk07 = br.ReadUInt32();
            Unk08 = br.ReadUInt32();//0
            Unk09 = br.ReadSingle();

            if (Unk02 != 0)
            { }
            if (Unk05 != 0)
            { }
            if (Unk08 != 0)
            { }
            
            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.ValueTag(sb, indent, "Unk09", FloatUtil.ToString(Unk09));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = Xml.GetChildFloatAttribute(node, "Unk09", "value");
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk01, Unk04, Unk07 };
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk27Item : IMetaXmlItem
    {
        public int Unk1 { get; set; }
        public int Unk2 { get; set; }

        public Dat151Unk27Item()
        { }
        public Dat151Unk27Item(BinaryReader br)
        {
            Unk1 = br.ReadInt32();
            Unk2 = br.ReadInt32();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Unk1);
            bw.Write(Unk2);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
            RelXml.ValueTag(sb, indent, "Unk2", Unk2.ToString());
        }
        public void ReadXml(XmlNode node)
        {
            Unk1 = Xml.GetChildIntAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildIntAttribute(node, "Unk2", "value");
        }
        public override string ToString()
        {
            return Unk1.ToString() + ": " + Unk2.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk27 : Dat151RelData
    {
        public int ItemCount { get; set; }
        public Dat151Unk27Item[] Items { get; set; }

        public Dat151Unk27(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk27;
            TypeID = (byte)Type;
        }
        public Dat151Unk27(RelData d, BinaryReader br) : base(d, br)
        {
            ItemCount = br.ReadInt32();
            Items = new Dat151Unk27Item[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151Unk27Item(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Items = XmlRel.ReadItemArray<Dat151Unk27Item>(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk28 : Dat151RelData
    {
        public MetaHash Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }
        public float Unk04 { get; set; }
        public MetaHash Unk05 { get; set; }
        public int Unk06 { get; set; }
        public MetaHash Unk07 { get; set; }
        public float Unk08 { get; set; }

        public Dat151Unk28(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk28;
            TypeID = (byte)Type;
        }
        public Dat151Unk28(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadUInt32();
            Unk03 = br.ReadUInt32();
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadUInt32();
            Unk06 = br.ReadInt32();
            Unk07 = br.ReadUInt32();
            Unk08 = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", Unk06.ToString());
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.ValueTag(sb, indent, "Unk08", FloatUtil.ToString(Unk08));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = Xml.GetChildIntAttribute(node, "Unk06", "value");
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Unk08 = Xml.GetChildFloatAttribute(node, "Unk08", "value");
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk01, Unk02, Unk03, Unk05, Unk07 };
        }
    }
    [TC(typeof(EXP))] public class Dat151RaceToPedVoiceGroup : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public MetaHash Universal { get; set; }//0
        public MetaHash White { get; set; }
        public MetaHash Black { get; set; }
        public MetaHash Chinese { get; set; }
        public MetaHash Latino { get; set; }
        public MetaHash Arabic { get; set; }//0 I think this might be "ara", by analogy with texids
        public MetaHash Baltic { get; set; }//0
        public MetaHash Jamaican { get; set; }//0
        public MetaHash Korean { get; set; }
        public MetaHash Italian { get; set; }//0
        public MetaHash Pakistani { get; set; }
        public int ItemCount { get; set; }
        public MetaHash[] Items { get; set; }//PedType

        public Dat151RaceToPedVoiceGroup(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.RaceToPedVoiceGroup;
            TypeID = (byte)Type;
        }
        public Dat151RaceToPedVoiceGroup(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Universal = br.ReadUInt32();//0
            White = br.ReadUInt32();
            Black = br.ReadUInt32();
            Chinese = br.ReadUInt32();
            Latino = br.ReadUInt32();
            Arabic = br.ReadUInt32();//0
            Baltic = br.ReadUInt32();//0
            Jamaican = br.ReadUInt32();//0
            Korean = br.ReadUInt32();
            Italian = br.ReadUInt32();//0
            Pakistani = br.ReadUInt32();
            ItemCount = br.ReadInt32();
            Items = new MetaHash[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = br.ReadUInt32();
            }

            if (Universal != 0)
            { }
            if (Arabic != 0)
            { }
            if (Baltic != 0)
            { }
            if (Jamaican != 0)
            { }
            if (Italian != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Universal);
            bw.Write(White);
            bw.Write(Black);
            bw.Write(Chinese);
            bw.Write(Latino);
            bw.Write(Arabic);
            bw.Write(Baltic);
            bw.Write(Jamaican);
            bw.Write(Korean);
            bw.Write(Italian);
            bw.Write(Pakistani);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                bw.Write(Items[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.StringTag(sb, indent, "Universal", RelXml.HashString(Universal));
            RelXml.StringTag(sb, indent, "White", RelXml.HashString(White));
            RelXml.StringTag(sb, indent, "Black", RelXml.HashString(Black));
            RelXml.StringTag(sb, indent, "Chinese", RelXml.HashString(Chinese));
            RelXml.StringTag(sb, indent, "Latino", RelXml.HashString(Latino));
            RelXml.StringTag(sb, indent, "Arabic", RelXml.HashString(Arabic));
            RelXml.StringTag(sb, indent, "Baltic", RelXml.HashString(Baltic));
            RelXml.StringTag(sb, indent, "Jamaican", RelXml.HashString(Jamaican));
            RelXml.StringTag(sb, indent, "Korean", RelXml.HashString(Korean));
            RelXml.StringTag(sb, indent, "Italian", RelXml.HashString(Italian));
            RelXml.StringTag(sb, indent, "Pakistani", RelXml.HashString(Pakistani));
            RelXml.WriteHashItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Universal = XmlRel.GetHash(Xml.GetChildInnerText(node, "Universal"));
            White = XmlRel.GetHash(Xml.GetChildInnerText(node, "White"));
            Black = XmlRel.GetHash(Xml.GetChildInnerText(node, "Black"));
            Chinese = XmlRel.GetHash(Xml.GetChildInnerText(node, "Chinese"));
            Latino = XmlRel.GetHash(Xml.GetChildInnerText(node, "Latino"));
            Arabic = XmlRel.GetHash(Xml.GetChildInnerText(node, "Arabic"));
            Baltic = XmlRel.GetHash(Xml.GetChildInnerText(node, "Baltic"));
            Jamaican = XmlRel.GetHash(Xml.GetChildInnerText(node, "Jamaican"));
            Korean = XmlRel.GetHash(Xml.GetChildInnerText(node, "Korean"));
            Italian = XmlRel.GetHash(Xml.GetChildInnerText(node, "Italian"));
            Pakistani = XmlRel.GetHash(Xml.GetChildInnerText(node, "Pakistani"));
            Items = XmlRel.ReadHashItemArray(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            list.AddRange(new[] { Universal, White, Black, Chinese, Latino, Arabic, Baltic, Jamaican, Korean, Italian, Pakistani });
            if (Items != null) list.AddRange(Items);
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151PedType : Dat151RelData
    {
        public FlagsUint Flags { get; set; }

        public Dat151PedType(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.PedType;
            TypeID = (byte)Type;
        }
        public Dat151PedType(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151PoliceScannerReportItem : IMetaXmlItem
    {
        public MetaHash Unk1 { get; set; }
        public short Unk2 { get; set; }
        public short Unk3 { get; set; }

        public Dat151PoliceScannerReportItem()
        { }
        public Dat151PoliceScannerReportItem(BinaryReader br)
        {
            Unk1 = br.ReadUInt32();
            Unk2 = br.ReadInt16();
            Unk3 = br.ReadInt16();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(Unk3);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk1", RelXml.HashString(Unk1));
            RelXml.ValueTag(sb, indent, "Unk2", Unk2.ToString());
            RelXml.ValueTag(sb, indent, "Unk3", Unk3.ToString());
        }
        public void ReadXml(XmlNode node)
        {
            Unk1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk1"));
            Unk2 = (short)Xml.GetChildIntAttribute(node, "Unk2", "value");
            Unk3 = (short)Xml.GetChildIntAttribute(node, "Unk3", "value");
        }
        public override string ToString()
        {
            return Unk1.ToString() + ": " + Unk2.ToString() + ", " + Unk3.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat151PoliceScannerReport : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public int ItemCount { get; set; }
        public Dat151PoliceScannerReportItem[] Items { get; set; }

        public Dat151PoliceScannerReport(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.PoliceScannerReport;
            TypeID = (byte)Type;
        }
        public Dat151PoliceScannerReport(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            ItemCount = br.ReadInt32();
            Items = new Dat151PoliceScannerReportItem[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151PoliceScannerReportItem(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Items = XmlRel.ReadItemArray<Dat151PoliceScannerReportItem>(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
        public override MetaHash[] GetSoundHashes()
        {
            var list = new List<MetaHash>();
            if (Items != null)
            {
                foreach (var item in Items)
                {
                    list.Add(item.Unk1);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151PoliceScannerLocation : Dat151RelData
    {
        public MetaHash Unk01 { get; set; }//0
        public MetaHash Unk02 { get; set; }//0
        public MetaHash Unk03 { get; set; }//0
        public Vector3 Position { get; set; }
        public MetaHash Unk04 { get; set; }//0
        public float Unk05 { get; set; }
        public float Unk06 { get; set; }
        public int Unk07 { get; set; }
        public MetaHash Unk08 { get; set; }
        public MetaHash Unk09 { get; set; }
        public MetaHash Unk10 { get; set; }//0
        public MetaHash Unk11 { get; set; }//0
        public MetaHash Unk12 { get; set; }//0

        public Dat151PoliceScannerLocation(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.PoliceScannerLocation;
            TypeID = (byte)Type;
        }
        public Dat151PoliceScannerLocation(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();//0
            Unk02 = br.ReadUInt32();//0
            Unk03 = br.ReadUInt32();//0
            Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            Unk04 = br.ReadUInt32();//0
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadSingle();
            Unk07 = br.ReadInt32();
            Unk08 = br.ReadUInt32();
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadUInt32();//0
            Unk11 = br.ReadUInt32();//0
            Unk12 = br.ReadUInt32();//0

            if (Unk01 != 0)
            { }
            if (Unk02 != 0)
            { }
            if (Unk03 != 0)
            { }
            if (Unk04 != 0)
            { }
            if (Unk10 != 0)
            { }
            if (Unk11 != 0)
            { }
            if (Unk12 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Position.X);
            bw.Write(Position.Y);
            bw.Write(Position.Z);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.SelfClosingTag(sb, indent, "Position " + FloatUtil.GetVector3XmlString(Position));
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
            RelXml.StringTag(sb, indent, "Unk11", RelXml.HashString(Unk11));
            RelXml.StringTag(sb, indent, "Unk12", RelXml.HashString(Unk12));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Position = Xml.GetChildVector3Attributes(node, "Position");
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildIntAttribute(node, "Unk07", "value");
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
            Unk11 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk11"));
            Unk12 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk12"));
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk08, Unk09 };
        }
    }
    [TC(typeof(EXP))] public class Dat151PoliceScannerLocationList : Dat151RelData
    {
        public int ItemCount { get; set; }
        public MetaHash[] Items { get; set; }

        public Dat151PoliceScannerLocationList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.PoliceScannerLocationList;
            TypeID = (byte)Type;
        }
        public Dat151PoliceScannerLocationList(RelData d, BinaryReader br) : base(d, br)
        {
            ItemCount = br.ReadInt32();
            Items = new MetaHash[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = br.ReadUInt32();
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                bw.Write(Items[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteHashItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Items = XmlRel.ReadHashItemArray(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
        public override MetaHash[] GetGameHashes()
        {
            return Items;
        }
    }
    [TC(typeof(EXP))] public class Dat151AmbientStreamListItem : IMetaXmlItem
    {
        public MetaHash WaveSlot { get; set; }//eg. amb_stream_bird_01  (from audioconfig)
        public MetaHash BankName { get; set; }//eg. streamed_birds  (also in AmbienceBankMap)
        public int Unk3 { get; set; }

        public Dat151AmbientStreamListItem()
        { }
        public Dat151AmbientStreamListItem(BinaryReader br)
        {
            WaveSlot = br.ReadUInt32();
            BankName = br.ReadUInt32();
            Unk3 = br.ReadInt32();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(WaveSlot);
            bw.Write(BankName);
            bw.Write(Unk3);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "WaveSlot", RelXml.HashString(WaveSlot));
            RelXml.StringTag(sb, indent, "BankName", RelXml.HashString(BankName));
            RelXml.ValueTag(sb, indent, "Unk3", Unk3.ToString());
        }
        public void ReadXml(XmlNode node)
        {
            WaveSlot = XmlRel.GetHash(Xml.GetChildInnerText(node, "WaveSlot"));
            BankName = XmlRel.GetHash(Xml.GetChildInnerText(node, "BankName"));
            Unk3 = Xml.GetChildIntAttribute(node, "Unk3", "value");
        }
        public override string ToString()
        {
            return WaveSlot.ToString() + ", " + BankName.ToString() + ", " + Unk3.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat151AmbientStreamList : Dat151RelData //contains eg amb_stream_bird_01
    {
        public int ItemCount { get; set; }
        public Dat151AmbientStreamListItem[] Items { get; set; }

        public Dat151AmbientStreamList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.AmbientStreamList;
            TypeID = (byte)Type;
        }
        public Dat151AmbientStreamList(RelData d, BinaryReader br) : base(d, br)
        {
            ItemCount = br.ReadInt32();
            Items = new Dat151AmbientStreamListItem[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151AmbientStreamListItem(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Items = XmlRel.ReadItemArray<Dat151AmbientStreamListItem>(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
    }
    [TC(typeof(EXP))] public class Dat151AmbienceBankMap : Dat151RelData //ambience_bank_map_autogenerated
    {
        public int ItemCount { get; set; }
        public Dat151HashPair[] Items { get; set; }//AwcName, BankName

        public Dat151AmbienceBankMap(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.AmbienceBankMap;
            TypeID = (byte)Type;
        }
        public Dat151AmbienceBankMap(RelData d, BinaryReader br) : base(d, br)
        {
            ItemCount = br.ReadInt32();
            Items = new Dat151HashPair[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151HashPair(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Items = XmlRel.ReadItemArray<Dat151HashPair>(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
    }
    [TC(typeof(EXP))] public class Dat151AmbientZoneParams : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public MetaHash Unk01 { get; set; }//0
        public float Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }//0
        public float Unk04 { get; set; }
        public float Unk05 { get; set; }
        public float Unk06 { get; set; }
        public float Unk07 { get; set; }
        public MetaHash Unk08 { get; set; }//0
        public MetaHash Unk09 { get; set; }//0
        public MetaHash Unk10 { get; set; }//0

        public Dat151AmbientZoneParams(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.AmbientZoneParams;
            TypeID = (byte)Type;
        }
        public Dat151AmbientZoneParams(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Unk01 = br.ReadUInt32();//0
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadUInt32();//0
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadSingle();
            Unk07 = br.ReadSingle();
            Unk08 = br.ReadUInt32();//0
            Unk09 = br.ReadUInt32();//0
            Unk10 = br.ReadUInt32();//0

            if (Unk01 != 0)
            { }
            if (Unk03 != 0)
            { }
            if (Unk08 != 0)
            { }
            if (Unk09 != 0)
            { }
            if (Unk10 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", FloatUtil.ToString(Unk07));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildFloatAttribute(node, "Unk07", "value");
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
        }
    }
    [TC(typeof(EXP))] public class Dat151InteriorRoomParams : Dat151RelData
    {
        public float Unk01 { get; set; }
        public float Unk02 { get; set; }
        public int Unk03 { get; set; }
        public int Unk04 { get; set; }
        public float Unk05 { get; set; }

        public Dat151InteriorRoomParams(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.InteriorRoomParams;
            TypeID = (byte)Type;
        }
        public Dat151InteriorRoomParams(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadSingle();
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadInt32();
            Unk04 = br.ReadInt32();
            Unk05 = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", FloatUtil.ToString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildFloatAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildIntAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildIntAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151DoorParams : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public float Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }//0
        public float Unk03 { get; set; }
        public float Unk04 { get; set; }
        public float Unk05 { get; set; }
        public float Unk06 { get; set; }
        public float Unk07 { get; set; }
        public int Unk08 { get; set; }

        public Dat151DoorParams(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.DoorParams;
            TypeID = (byte)Type;
        }
        public Dat151DoorParams(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Unk01 = br.ReadSingle();
            Unk02 = br.ReadUInt32();//0
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadSingle();
            Unk07 = br.ReadSingle();
            Unk08 = br.ReadInt32();

            if (Unk02 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", FloatUtil.ToString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", FloatUtil.ToString(Unk07));
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = Xml.GetChildFloatAttribute(node, "Unk01", "value");
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildFloatAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildIntAttribute(node, "Unk08", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151Climbing : Dat151RelData
    {
        public MetaHash Launch { get; set; }
        public MetaHash Foot { get; set; }
        public MetaHash Knee { get; set; }
        public MetaHash Scrape { get; set; }
        public MetaHash Hand { get; set; }

        public Dat151Climbing(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Climbing;
            TypeID = (byte)Type;
        }
        public Dat151Climbing(RelData d, BinaryReader br) : base(d, br)
        {
            Launch = br.ReadUInt32();
            Foot = br.ReadUInt32();
            Knee = br.ReadUInt32();
            Scrape = br.ReadUInt32();
            Hand = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Launch);
            bw.Write(Foot);
            bw.Write(Knee);
            bw.Write(Scrape);
            bw.Write(Hand);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Launch", RelXml.HashString(Launch));
            RelXml.StringTag(sb, indent, "Foot", RelXml.HashString(Foot));
            RelXml.StringTag(sb, indent, "Knee", RelXml.HashString(Knee));
            RelXml.StringTag(sb, indent, "Scrape", RelXml.HashString(Scrape));
            RelXml.StringTag(sb, indent, "Hand", RelXml.HashString(Hand));
        }
        public override void ReadXml(XmlNode node)
        {
            Launch = XmlRel.GetHash(Xml.GetChildInnerText(node, "Launch"));
            Foot = XmlRel.GetHash(Xml.GetChildInnerText(node, "Foot"));
            Knee = XmlRel.GetHash(Xml.GetChildInnerText(node, "Knee"));
            Scrape = XmlRel.GetHash(Xml.GetChildInnerText(node, "Scrape"));
            Hand = XmlRel.GetHash(Xml.GetChildInnerText(node, "Hand"));
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Launch, Foot, Knee, Scrape, Hand };
        }
    }
    [TC(typeof(EXP))] public class Dat151WeatherType : Dat151RelData
    {
        public float Unk01 { get; set; }
        public float Unk02 { get; set; }
        public float Unk03 { get; set; }
        public float Unk04 { get; set; }
        public float Unk05 { get; set; }
        public MetaHash Unk06 { get; set; }
        public MetaHash Scene { get; set; }
        public MetaHash Unk08 { get; set; }
        public int ItemCount { get; set; }
        public MetaHash[] Items { get; set; }

        public Dat151WeatherType(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.WeatherType;
            TypeID = (byte)Type;
        }
        public Dat151WeatherType(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadSingle();
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadUInt32();
            Scene = br.ReadUInt32();
            Unk08 = br.ReadUInt32();
            ItemCount = br.ReadInt32();
            Items = new MetaHash[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = br.ReadUInt32();
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Scene);
            bw.Write(Unk08);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                bw.Write(Items[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", FloatUtil.ToString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.StringTag(sb, indent, "Scene", RelXml.HashString(Scene));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.WriteHashItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildFloatAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Scene = XmlRel.GetHash(Xml.GetChildInnerText(node, "Scene"));
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Items = XmlRel.ReadHashItemArray(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
        public override MetaHash[] GetMixerHashes()
        {
            return new[] { Scene };
        }
        public override MetaHash[] GetSoundHashes()
        {
            var list = new List<MetaHash>();
            list.Add(Unk06);
            list.Add(Unk08);
            if (Items != null)
            {
                list.AddRange(Items);
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151StemMix : Dat151RelData
    {
        public short Stem1Volume { get; set; }
        public short Stem2Volume { get; set; }
        public short Stem3Volume { get; set; }
        public short Stem4Volume { get; set; }
        public short Stem5Volume { get; set; }
        public short Stem6Volume { get; set; }
        public short Stem7Volume { get; set; }
        public short Stem8Volume { get; set; }

        public Dat151StemMix(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.StemMix;
            TypeID = (byte)Type;
        }
        public Dat151StemMix(RelData d, BinaryReader br) : base(d, br)
        {
            Stem1Volume = br.ReadInt16();
            Stem2Volume = br.ReadInt16();
            Stem3Volume = br.ReadInt16();
            Stem4Volume = br.ReadInt16();
            Stem5Volume = br.ReadInt16();
            Stem6Volume = br.ReadInt16();
            Stem7Volume = br.ReadInt16();
            Stem8Volume = br.ReadInt16();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Stem1Volume);
            bw.Write(Stem2Volume);
            bw.Write(Stem3Volume);
            bw.Write(Stem4Volume);
            bw.Write(Stem5Volume);
            bw.Write(Stem6Volume);
            bw.Write(Stem7Volume);
            bw.Write(Stem8Volume);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Stem1Volume", Stem1Volume.ToString());
            RelXml.ValueTag(sb, indent, "Stem2Volume", Stem2Volume.ToString());
            RelXml.ValueTag(sb, indent, "Stem3Volume", Stem3Volume.ToString());
            RelXml.ValueTag(sb, indent, "Stem4Volume", Stem4Volume.ToString());
            RelXml.ValueTag(sb, indent, "Stem5Volume", Stem5Volume.ToString());
            RelXml.ValueTag(sb, indent, "Stem6Volume", Stem6Volume.ToString());
            RelXml.ValueTag(sb, indent, "Stem7Volume", Stem7Volume.ToString());
            RelXml.ValueTag(sb, indent, "Stem8Volume", Stem8Volume.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Stem1Volume = (short)Xml.GetChildIntAttribute(node, "Stem1Volume", "value");
            Stem2Volume = (short)Xml.GetChildIntAttribute(node, "Stem2Volume", "value");
            Stem3Volume = (short)Xml.GetChildIntAttribute(node, "Stem3Volume", "value");
            Stem4Volume = (short)Xml.GetChildIntAttribute(node, "Stem4Volume", "value");
            Stem5Volume = (short)Xml.GetChildIntAttribute(node, "Stem5Volume", "value");
            Stem6Volume = (short)Xml.GetChildIntAttribute(node, "Stem6Volume", "value");
            Stem7Volume = (short)Xml.GetChildIntAttribute(node, "Stem7Volume", "value");
            Stem8Volume = (short)Xml.GetChildIntAttribute(node, "Stem8Volume", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151MusicBeat : Dat151RelData
    {
        public ushort Unk01 { get; set; } 

        public Dat151MusicBeat(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.MusicBeat;
            TypeID = (byte)Type;
        }
        public Dat151MusicBeat(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt16();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = (ushort)Xml.GetChildUIntAttribute(node, "Unk01", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151MusicBar : Dat151RelData
    {
        public int Unk01 { get; set; } //beat count?
        public int Unk02 { get; set; }

        public Dat151MusicBar(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.MusicBar;
            TypeID = (byte)Type;
        }
        public Dat151MusicBar(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadInt32();
            Unk02 = br.ReadInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildIntAttribute(node, "Unk02", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151DependentAmbience : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public MetaHash ChildSound1 { get; set; }
        public MetaHash ChildSound2 { get; set; }
        public MetaHash ChildSound3 { get; set; }
        public MetaHash ChildSound4 { get; set; }
        public float Unk05 { get; set; }
        public MetaHash Unk06 { get; set; }
        public MetaHash Unk07 { get; set; }
        public MetaHash Unk08 { get; set; }
        public MetaHash Unk09 { get; set; }
        public MetaHash Unk10 { get; set; }
        public MetaHash Unk11 { get; set; }
        public MetaHash Unk12 { get; set; }
        public MetaHash Unk13 { get; set; }
        public float Unk14 { get; set; }
        public MetaHash Unk15 { get; set; }
        public MetaHash Unk16 { get; set; }
        public MetaHash Unk17 { get; set; }
        public float Unk18 { get; set; }

        public Dat151DependentAmbience(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.DependentAmbience;
            TypeID = (byte)Type;
        }
        public Dat151DependentAmbience(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            ChildSound1 = br.ReadUInt32();
            ChildSound2 = br.ReadUInt32();
            ChildSound3 = br.ReadUInt32();
            ChildSound4 = br.ReadUInt32();
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadUInt32();
            Unk07 = br.ReadUInt32();
            Unk08 = br.ReadUInt32();
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadUInt32();
            Unk11 = br.ReadUInt32();
            Unk12 = br.ReadUInt32();
            Unk13 = br.ReadUInt32();
            Unk14 = br.ReadSingle();
            Unk15 = br.ReadUInt32();
            Unk16 = br.ReadUInt32();
            Unk17 = br.ReadUInt32();
            Unk18 = br.ReadSingle();

            if (ChildSound2 != 0)
            { }
            if (ChildSound3 != 0)
            { }
            if (ChildSound4 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(ChildSound1);
            bw.Write(ChildSound2);
            bw.Write(ChildSound3);
            bw.Write(ChildSound4);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.StringTag(sb, indent, "ChildSound1", RelXml.HashString(ChildSound1));
            RelXml.StringTag(sb, indent, "ChildSound2", RelXml.HashString(ChildSound2));
            RelXml.StringTag(sb, indent, "ChildSound3", RelXml.HashString(ChildSound3));
            RelXml.StringTag(sb, indent, "ChildSound4", RelXml.HashString(ChildSound4));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
            RelXml.StringTag(sb, indent, "Unk11", RelXml.HashString(Unk11));
            RelXml.StringTag(sb, indent, "Unk12", RelXml.HashString(Unk12));
            RelXml.StringTag(sb, indent, "Unk13", RelXml.HashString(Unk13));
            RelXml.ValueTag(sb, indent, "Unk14", FloatUtil.ToString(Unk14));
            RelXml.StringTag(sb, indent, "Unk15", RelXml.HashString(Unk15));
            RelXml.StringTag(sb, indent, "Unk16", RelXml.HashString(Unk16));
            RelXml.StringTag(sb, indent, "Unk17", RelXml.HashString(Unk17));
            RelXml.ValueTag(sb, indent, "Unk18", FloatUtil.ToString(Unk18));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            ChildSound1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound1"));
            ChildSound2 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound2"));
            ChildSound3 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound3"));
            ChildSound4 = XmlRel.GetHash(Xml.GetChildInnerText(node, "ChildSound4"));
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
            Unk11 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk11"));
            Unk12 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk12"));
            Unk13 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk13"));
            Unk14 = Xml.GetChildFloatAttribute(node, "Unk14", "value");
            Unk15 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk15"));
            Unk16 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk16"));
            Unk17 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk17"));
            Unk18 = Xml.GetChildFloatAttribute(node, "Unk18", "value");
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { Unk06, Unk07, Unk08, Unk09, Unk10, Unk11, Unk12, Unk13, Unk15, Unk16, Unk17 };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { ChildSound1, ChildSound2, ChildSound3, ChildSound4 };
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk72 : Dat151RelData
    {
        public int Unk01 { get; set; }
        public float Unk02 { get; set; }
        public float Unk03 { get; set; }
        public float Unk04 { get; set; }
        public float Unk05 { get; set; }
        public float Unk06 { get; set; }
        public float Unk07 { get; set; }
        public float Unk08 { get; set; }
        public float Unk09 { get; set; }
        public MetaHash Unk10 { get; set; }//0
        public MetaHash Unk11 { get; set; }//0
        public MetaHash Unk12 { get; set; }
        public MetaHash Unk13 { get; set; }
        public MetaHash Unk14 { get; set; }
        public MetaHash Unk15 { get; set; }

        public Dat151Unk72(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk72;
            TypeID = (byte)Type;
        }
        public Dat151Unk72(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadInt32();
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadSingle();
            Unk07 = br.ReadSingle();
            Unk08 = br.ReadSingle();
            Unk09 = br.ReadSingle();
            Unk10 = br.ReadUInt32();//0
            Unk11 = br.ReadUInt32();//0
            Unk12 = br.ReadUInt32();
            Unk13 = br.ReadUInt32();
            Unk14 = br.ReadUInt32();
            Unk15 = br.ReadUInt32();

            if (Unk10 != 0)
            { }
            if (Unk11 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", FloatUtil.ToString(Unk07));
            RelXml.ValueTag(sb, indent, "Unk08", FloatUtil.ToString(Unk08));
            RelXml.ValueTag(sb, indent, "Unk09", FloatUtil.ToString(Unk09));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
            RelXml.StringTag(sb, indent, "Unk11", RelXml.HashString(Unk11));
            RelXml.StringTag(sb, indent, "Unk12", RelXml.HashString(Unk12));
            RelXml.StringTag(sb, indent, "Unk13", RelXml.HashString(Unk13));
            RelXml.StringTag(sb, indent, "Unk14", RelXml.HashString(Unk14));
            RelXml.StringTag(sb, indent, "Unk15", RelXml.HashString(Unk15));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildFloatAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildFloatAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildFloatAttribute(node, "Unk09", "value");
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
            Unk11 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk11"));
            Unk12 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk12"));
            Unk13 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk13"));
            Unk14 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk14"));
            Unk15 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk15"));
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk12, Unk13, Unk14, Unk15 };
        }
    }
    [TC(typeof(EXP))] public class Dat151AnimalSoundsItem : IMetaXmlItem
    {
        public byte Unk1 { get; set; }
        public byte ItemCount1 { get; set; } //indicates how many are used
        public Dat151HashFloat[] Items1 { get; set; } //always array of 8  - probably links to speech.dat somehow
        public byte ItemCount2 { get; set; } //indicates how many are used
        public Dat151HashFloat[] Items2 { get; set; } //always array of 8

        public Dat151AnimalSoundsItem()
        { }
        public Dat151AnimalSoundsItem(BinaryReader br)
        {
            Unk1 = br.ReadByte();
            ItemCount1 = br.ReadByte();
            Items1 = new Dat151HashFloat[8];
            for (int i = 0; i < 8; i++)
            {
                Items1[i] = new Dat151HashFloat(br);
            }
            ItemCount2 = br.ReadByte();
            Items2 = new Dat151HashFloat[8];
            for (int i = 0; i < 8; i++)
            {
                Items2[i] = new Dat151HashFloat(br);
            }
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Unk1);
            bw.Write(ItemCount1);
            for (int i = 0; i < 8; i++)
            {
                Items1[i].Write(bw);
            }
            bw.Write(ItemCount2);
            for (int i = 0; i < 8; i++)
            {
                Items2[i].Write(bw);
            }
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
            RelXml.ValueTag(sb, indent, "ItemCount1", ItemCount1.ToString());
            RelXml.WriteItemArray(sb, Items1, indent, "Items1");
            RelXml.ValueTag(sb, indent, "ItemCount2", ItemCount2.ToString());
            RelXml.WriteItemArray(sb, Items2, indent, "Items2");
        }
        public void ReadXml(XmlNode node)
        {
            Unk1 = (byte)Xml.GetChildUIntAttribute(node, "Unk1", "value");
            ItemCount1 = (byte)Xml.GetChildUIntAttribute(node, "ItemCount1", "value");
            Items1 = XmlRel.ReadItemArray<Dat151HashFloat>(node, "Items1");
            ItemCount2 = (byte)Xml.GetChildUIntAttribute(node, "ItemCount2", "value");
            Items2 = XmlRel.ReadItemArray<Dat151HashFloat>(node, "Items2");
            //probably should make an error if Items1/2 are not an array of 8...
        }
        public override string ToString()
        {
            return Unk1.ToString() + ": " + ItemCount1.ToString() + ", " + ItemCount2.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat151AnimalSounds : Dat151RelData
    {
        public byte ItemCount { get; set; }
        public Dat151AnimalSoundsItem[] Items { get; set; }

        public Dat151AnimalSounds(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.AnimalSounds;
            TypeID = (byte)Type;
        }
        public Dat151AnimalSounds(RelData d, BinaryReader br) : base(d, br)
        {
            ItemCount = br.ReadByte();//1
            Items = new Dat151AnimalSoundsItem[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151AnimalSoundsItem(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Items = XmlRel.ReadItemArray<Dat151AnimalSoundsItem>(node, "Items");
            ItemCount = (byte)(Items?.Length ?? 0);
        }
    }
    [TC(typeof(EXP))] public class Dat151VehicleScannerColourList : Dat151RelData
    {
        public MetaHash Black { get; set; }
        public MetaHash Blue { get; set; }
        public MetaHash Brown { get; set; }
        public MetaHash Beige { get; set; }
        public MetaHash Graphite { get; set; }
        public MetaHash Green { get; set; }
        public MetaHash Grey { get; set; }
        public MetaHash Orange { get; set; }
        public MetaHash Pink { get; set; }
        public MetaHash Red { get; set; }
        public MetaHash Silver { get; set; }
        public MetaHash White { get; set; }
        public MetaHash Yellow { get; set; }
        public MetaHash MetallicBlack { get; set; }
        public MetaHash MetallicBlue { get; set; }
        public MetaHash MetallicBrown { get; set; }
        public MetaHash MetallicBeige { get; set; }//0
        public MetaHash MetallicGraphite { get; set; }//0
        public MetaHash MetallicGreen { get; set; }
        public MetaHash MetallicGrey { get; set; }
        public MetaHash MetallicOrange { get; set; }//0
        public MetaHash MetallicPink { get; set; }//0
        public MetaHash MetallicRed { get; set; }
        public MetaHash MetallicSilver { get; set; }
        public MetaHash MetallicWhite { get; set; }//0
        public MetaHash MetallicYellow { get; set; }
        public MetaHash LightBlack { get; set; }//0
        public MetaHash LightBlue { get; set; }
        public MetaHash LightBrown { get; set; }
        public MetaHash LightBeige { get; set; }//0
        public MetaHash LightGraphite { get; set; }//0
        public MetaHash LightGreen { get; set; }
        public MetaHash LightGrey { get; set; }
        public MetaHash LightOrange { get; set; }
        public MetaHash LightPink { get; set; }//0
        public MetaHash LightRed { get; set; }
        public MetaHash LightSilver { get; set; }
        public MetaHash LightWhite { get; set; }//0
        public MetaHash LightYellow { get; set; }
        public MetaHash DarkBlack { get; set; }//0
        public MetaHash DarkBlue { get; set; }
        public MetaHash DarkBrown { get; set; }
        public MetaHash DarkBeige { get; set; }//0
        public MetaHash DarkGraphite { get; set; }//0
        public MetaHash DarkGreen { get; set; }
        public MetaHash DarkGrey { get; set; }
        public MetaHash DarkOrange { get; set; }
        public MetaHash DarkPink { get; set; }//0
        public MetaHash DarkRed { get; set; }
        public MetaHash DarkSilver { get; set; }
        public MetaHash DarkWhite { get; set; }//0
        public MetaHash DarkYellow { get; set; }
        public MetaHash Unk53 { get; set; }//0
        public MetaHash BeatUp { get; set; }
        public MetaHash Unk55 { get; set; }//0
        public MetaHash Custom { get; set; }
        public MetaHash Unk57 { get; set; }//0
        public MetaHash Unk58 { get; set; }//0
        public MetaHash Unk59 { get; set; }//0
        public MetaHash Dirty { get; set; }
        public MetaHash Unk61 { get; set; }//0
        public MetaHash Mint { get; set; }
        public MetaHash Unk63 { get; set; }//0
        public MetaHash Unk64 { get; set; }//0
        public MetaHash Unk65 { get; set; }//0
        public MetaHash Rusty { get; set; }

        public Dat151VehicleScannerColourList(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.VehicleScannerColourList;
            TypeID = (byte)Type;
        }
        public Dat151VehicleScannerColourList(RelData d, BinaryReader br) : base(d, br)
        {
            Black = br.ReadUInt32();
            Blue = br.ReadUInt32();
            Brown = br.ReadUInt32();
            Beige = br.ReadUInt32();
            Graphite = br.ReadUInt32();
            Green = br.ReadUInt32();
            Grey = br.ReadUInt32();
            Orange = br.ReadUInt32();
            Pink = br.ReadUInt32();
            Red = br.ReadUInt32();
            Silver = br.ReadUInt32();
            White = br.ReadUInt32();
            Yellow = br.ReadUInt32();
            MetallicBlack = br.ReadUInt32();
            MetallicBlue = br.ReadUInt32();
            MetallicBrown = br.ReadUInt32();
            MetallicBeige = br.ReadUInt32();//0
            MetallicGraphite = br.ReadUInt32();//0
            MetallicGreen = br.ReadUInt32();
            MetallicGrey = br.ReadUInt32();
            MetallicOrange = br.ReadUInt32();//0
            MetallicPink = br.ReadUInt32();//0
            MetallicRed = br.ReadUInt32();
            MetallicSilver = br.ReadUInt32();
            MetallicWhite = br.ReadUInt32();//0
            MetallicYellow = br.ReadUInt32();
            LightBlack = br.ReadUInt32();//0
            LightBlue = br.ReadUInt32();
            LightBrown = br.ReadUInt32();
            LightBeige = br.ReadUInt32();//0
            LightGraphite = br.ReadUInt32();//0
            LightGreen = br.ReadUInt32();
            LightGrey = br.ReadUInt32();
            LightOrange = br.ReadUInt32();
            LightPink = br.ReadUInt32();//0
            LightRed = br.ReadUInt32();
            LightSilver = br.ReadUInt32();
            LightWhite = br.ReadUInt32();//0
            LightYellow = br.ReadUInt32();
            DarkBlack = br.ReadUInt32();//0
            DarkBlue = br.ReadUInt32();
            DarkBrown = br.ReadUInt32();
            DarkBeige = br.ReadUInt32();//0
            DarkGraphite = br.ReadUInt32();//0
            DarkGreen = br.ReadUInt32();
            DarkGrey = br.ReadUInt32();
            DarkOrange = br.ReadUInt32();
            DarkPink = br.ReadUInt32();//0
            DarkRed = br.ReadUInt32();
            DarkSilver = br.ReadUInt32();
            DarkWhite = br.ReadUInt32();//0
            DarkYellow = br.ReadUInt32();
            Unk53 = br.ReadUInt32();//0
            BeatUp = br.ReadUInt32();
            Unk55 = br.ReadUInt32();//0
            Custom = br.ReadUInt32();
            Unk57 = br.ReadUInt32();//0
            Unk58 = br.ReadUInt32();//0
            Unk59 = br.ReadUInt32();//0
            Dirty = br.ReadUInt32();
            Unk61 = br.ReadUInt32();//0
            Mint = br.ReadUInt32();
            Unk63 = br.ReadUInt32();//0
            Unk64 = br.ReadUInt32();//0
            Unk65 = br.ReadUInt32();//0
            Rusty = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Black);
            bw.Write(Blue);
            bw.Write(Brown);
            bw.Write(Beige);
            bw.Write(Graphite);
            bw.Write(Green);
            bw.Write(Grey);
            bw.Write(Orange);
            bw.Write(Pink);
            bw.Write(Red);
            bw.Write(Silver);
            bw.Write(White);
            bw.Write(Yellow);
            bw.Write(MetallicBlack);
            bw.Write(MetallicBlue);
            bw.Write(MetallicBrown);
            bw.Write(MetallicBeige);
            bw.Write(MetallicGraphite);
            bw.Write(MetallicGreen);
            bw.Write(MetallicGrey);
            bw.Write(MetallicOrange);
            bw.Write(MetallicPink);
            bw.Write(MetallicRed);
            bw.Write(MetallicSilver);
            bw.Write(MetallicWhite);
            bw.Write(MetallicYellow);
            bw.Write(LightBlack);
            bw.Write(LightBlue);
            bw.Write(LightBrown);
            bw.Write(LightBeige);
            bw.Write(LightGraphite);
            bw.Write(LightGreen);
            bw.Write(LightGrey);
            bw.Write(LightOrange);
            bw.Write(LightPink);
            bw.Write(LightRed);
            bw.Write(LightSilver);
            bw.Write(LightWhite);
            bw.Write(LightYellow);
            bw.Write(DarkBlack);
            bw.Write(DarkBlue);
            bw.Write(DarkBrown);
            bw.Write(DarkBeige);
            bw.Write(DarkGraphite);
            bw.Write(DarkGreen);
            bw.Write(DarkGrey);
            bw.Write(DarkOrange);
            bw.Write(DarkPink);
            bw.Write(DarkRed);
            bw.Write(DarkSilver);
            bw.Write(DarkWhite);
            bw.Write(DarkYellow);
            bw.Write(Unk53);
            bw.Write(BeatUp);
            bw.Write(Unk55);
            bw.Write(Custom);
            bw.Write(Unk57);
            bw.Write(Unk58);
            bw.Write(Unk59);
            bw.Write(Dirty);
            bw.Write(Unk61);
            bw.Write(Mint);
            bw.Write(Unk63);
            bw.Write(Unk64);
            bw.Write(Unk65);
            bw.Write(Rusty);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Black", RelXml.HashString(Black));
            RelXml.StringTag(sb, indent, "Blue", RelXml.HashString(Blue));
            RelXml.StringTag(sb, indent, "Brown", RelXml.HashString(Brown));
            RelXml.StringTag(sb, indent, "Beige", RelXml.HashString(Beige));
            RelXml.StringTag(sb, indent, "Graphite", RelXml.HashString(Graphite));
            RelXml.StringTag(sb, indent, "Green", RelXml.HashString(Green));
            RelXml.StringTag(sb, indent, "Grey", RelXml.HashString(Grey));
            RelXml.StringTag(sb, indent, "Orange", RelXml.HashString(Orange));
            RelXml.StringTag(sb, indent, "Pink", RelXml.HashString(Pink));
            RelXml.StringTag(sb, indent, "Red", RelXml.HashString(Red));
            RelXml.StringTag(sb, indent, "Silver", RelXml.HashString(Silver));
            RelXml.StringTag(sb, indent, "White", RelXml.HashString(White));
            RelXml.StringTag(sb, indent, "Yellow", RelXml.HashString(Yellow));
            RelXml.StringTag(sb, indent, "MetallicBlack", RelXml.HashString(MetallicBlack));
            RelXml.StringTag(sb, indent, "MetallicBlue", RelXml.HashString(MetallicBlue));
            RelXml.StringTag(sb, indent, "MetallicBrown", RelXml.HashString(MetallicBrown));
            RelXml.StringTag(sb, indent, "MetallicBeige", RelXml.HashString(MetallicBeige));
            RelXml.StringTag(sb, indent, "MetallicGraphite", RelXml.HashString(MetallicGraphite));
            RelXml.StringTag(sb, indent, "MetallicGreen", RelXml.HashString(MetallicGreen));
            RelXml.StringTag(sb, indent, "MetallicGrey", RelXml.HashString(MetallicGrey));
            RelXml.StringTag(sb, indent, "MetallicOrange", RelXml.HashString(MetallicOrange));
            RelXml.StringTag(sb, indent, "MetallicPink", RelXml.HashString(MetallicPink));
            RelXml.StringTag(sb, indent, "MetallicRed", RelXml.HashString(MetallicRed));
            RelXml.StringTag(sb, indent, "MetallicSilver", RelXml.HashString(MetallicSilver));
            RelXml.StringTag(sb, indent, "MetallicWhite", RelXml.HashString(MetallicWhite));
            RelXml.StringTag(sb, indent, "MetallicYellow", RelXml.HashString(MetallicYellow));
            RelXml.StringTag(sb, indent, "LightBlack", RelXml.HashString(LightBlack));
            RelXml.StringTag(sb, indent, "LightBlue", RelXml.HashString(LightBlue));
            RelXml.StringTag(sb, indent, "LightBrown", RelXml.HashString(LightBrown));
            RelXml.StringTag(sb, indent, "LightBeige", RelXml.HashString(LightBeige));
            RelXml.StringTag(sb, indent, "LightGraphite", RelXml.HashString(LightGraphite));
            RelXml.StringTag(sb, indent, "LightGreen", RelXml.HashString(LightGreen));
            RelXml.StringTag(sb, indent, "LightGrey", RelXml.HashString(LightGrey));
            RelXml.StringTag(sb, indent, "LightOrange", RelXml.HashString(LightOrange));
            RelXml.StringTag(sb, indent, "LightPink", RelXml.HashString(LightPink));
            RelXml.StringTag(sb, indent, "LightRed", RelXml.HashString(LightRed));
            RelXml.StringTag(sb, indent, "LightSilver", RelXml.HashString(LightSilver));
            RelXml.StringTag(sb, indent, "LightWhite", RelXml.HashString(LightWhite));
            RelXml.StringTag(sb, indent, "LightYellow", RelXml.HashString(LightYellow));
            RelXml.StringTag(sb, indent, "DarkBlack", RelXml.HashString(DarkBlack));
            RelXml.StringTag(sb, indent, "DarkBlue", RelXml.HashString(DarkBlue));
            RelXml.StringTag(sb, indent, "DarkBrown", RelXml.HashString(DarkBrown));
            RelXml.StringTag(sb, indent, "DarkBeige", RelXml.HashString(DarkBeige));
            RelXml.StringTag(sb, indent, "DarkGraphite", RelXml.HashString(DarkGraphite));
            RelXml.StringTag(sb, indent, "DarkGreen", RelXml.HashString(DarkGreen));
            RelXml.StringTag(sb, indent, "DarkGrey", RelXml.HashString(DarkGrey));
            RelXml.StringTag(sb, indent, "DarkOrange", RelXml.HashString(DarkOrange));
            RelXml.StringTag(sb, indent, "DarkPink", RelXml.HashString(DarkPink));
            RelXml.StringTag(sb, indent, "DarkRed", RelXml.HashString(DarkRed));
            RelXml.StringTag(sb, indent, "DarkSilver", RelXml.HashString(DarkSilver));
            RelXml.StringTag(sb, indent, "DarkWhite", RelXml.HashString(DarkWhite));
            RelXml.StringTag(sb, indent, "DarkYellow", RelXml.HashString(DarkYellow));
            RelXml.StringTag(sb, indent, "Unk53", RelXml.HashString(Unk53));
            RelXml.StringTag(sb, indent, "BeatUp", RelXml.HashString(BeatUp));
            RelXml.StringTag(sb, indent, "Unk55", RelXml.HashString(Unk55));
            RelXml.StringTag(sb, indent, "Custom", RelXml.HashString(Custom));
            RelXml.StringTag(sb, indent, "Unk57", RelXml.HashString(Unk57));
            RelXml.StringTag(sb, indent, "Unk58", RelXml.HashString(Unk58));
            RelXml.StringTag(sb, indent, "Unk59", RelXml.HashString(Unk59));
            RelXml.StringTag(sb, indent, "Dirty", RelXml.HashString(Dirty));
            RelXml.StringTag(sb, indent, "Unk61", RelXml.HashString(Unk61));
            RelXml.StringTag(sb, indent, "Mint", RelXml.HashString(Mint));
            RelXml.StringTag(sb, indent, "Unk63", RelXml.HashString(Unk63));
            RelXml.StringTag(sb, indent, "Unk64", RelXml.HashString(Unk64));
            RelXml.StringTag(sb, indent, "Unk65", RelXml.HashString(Unk65));
            RelXml.StringTag(sb, indent, "Rusty", RelXml.HashString(Rusty));
        }
        public override void ReadXml(XmlNode node)
        {
            Black = XmlRel.GetHash(Xml.GetChildInnerText(node, "Black"));
            Blue = XmlRel.GetHash(Xml.GetChildInnerText(node, "Blue"));
            Brown = XmlRel.GetHash(Xml.GetChildInnerText(node, "Brown"));
            Beige = XmlRel.GetHash(Xml.GetChildInnerText(node, "Beige"));
            Graphite = XmlRel.GetHash(Xml.GetChildInnerText(node, "Graphite"));
            Green = XmlRel.GetHash(Xml.GetChildInnerText(node, "Green"));
            Grey = XmlRel.GetHash(Xml.GetChildInnerText(node, "Grey"));
            Orange = XmlRel.GetHash(Xml.GetChildInnerText(node, "Orange"));
            Pink = XmlRel.GetHash(Xml.GetChildInnerText(node, "Pink"));
            Red = XmlRel.GetHash(Xml.GetChildInnerText(node, "Red"));
            Silver = XmlRel.GetHash(Xml.GetChildInnerText(node, "Silver"));
            White = XmlRel.GetHash(Xml.GetChildInnerText(node, "White"));
            Yellow = XmlRel.GetHash(Xml.GetChildInnerText(node, "Yellow"));
            MetallicBlack = XmlRel.GetHash(Xml.GetChildInnerText(node, "MetallicBlack"));
            MetallicBlue = XmlRel.GetHash(Xml.GetChildInnerText(node, "MetallicBlue"));
            MetallicBrown = XmlRel.GetHash(Xml.GetChildInnerText(node, "MetallicBrown"));
            MetallicBeige = XmlRel.GetHash(Xml.GetChildInnerText(node, "MetallicBeige"));
            MetallicGraphite = XmlRel.GetHash(Xml.GetChildInnerText(node, "MetallicGraphite"));
            MetallicGreen = XmlRel.GetHash(Xml.GetChildInnerText(node, "MetallicGreen"));
            MetallicGrey = XmlRel.GetHash(Xml.GetChildInnerText(node, "MetallicGrey"));
            MetallicOrange = XmlRel.GetHash(Xml.GetChildInnerText(node, "MetallicOrange"));
            MetallicPink = XmlRel.GetHash(Xml.GetChildInnerText(node, "MetallicPink"));
            MetallicRed = XmlRel.GetHash(Xml.GetChildInnerText(node, "MetallicRed"));
            MetallicSilver = XmlRel.GetHash(Xml.GetChildInnerText(node, "MetallicSilver"));
            MetallicWhite = XmlRel.GetHash(Xml.GetChildInnerText(node, "MetallicWhite"));
            MetallicYellow = XmlRel.GetHash(Xml.GetChildInnerText(node, "MetallicYellow"));
            LightBlack = XmlRel.GetHash(Xml.GetChildInnerText(node, "LightBlack"));
            LightBlue = XmlRel.GetHash(Xml.GetChildInnerText(node, "LightBlue"));
            LightBrown = XmlRel.GetHash(Xml.GetChildInnerText(node, "LightBrown"));
            LightBeige = XmlRel.GetHash(Xml.GetChildInnerText(node, "LightBeige"));
            LightGraphite = XmlRel.GetHash(Xml.GetChildInnerText(node, "LightGraphite"));
            LightGreen = XmlRel.GetHash(Xml.GetChildInnerText(node, "LightGreen"));
            LightGrey = XmlRel.GetHash(Xml.GetChildInnerText(node, "LightGrey"));
            LightOrange = XmlRel.GetHash(Xml.GetChildInnerText(node, "LightOrange"));
            LightPink = XmlRel.GetHash(Xml.GetChildInnerText(node, "LightPink"));
            LightRed = XmlRel.GetHash(Xml.GetChildInnerText(node, "LightRed"));
            LightSilver = XmlRel.GetHash(Xml.GetChildInnerText(node, "LightSilver"));
            LightWhite = XmlRel.GetHash(Xml.GetChildInnerText(node, "LightWhite"));
            LightYellow = XmlRel.GetHash(Xml.GetChildInnerText(node, "LightYellow"));
            DarkBlack = XmlRel.GetHash(Xml.GetChildInnerText(node, "DarkBlack"));
            DarkBlue = XmlRel.GetHash(Xml.GetChildInnerText(node, "DarkBlue"));
            DarkBrown = XmlRel.GetHash(Xml.GetChildInnerText(node, "DarkBrown"));
            DarkBeige = XmlRel.GetHash(Xml.GetChildInnerText(node, "DarkBeige"));
            DarkGraphite = XmlRel.GetHash(Xml.GetChildInnerText(node, "DarkGraphite"));
            DarkGreen = XmlRel.GetHash(Xml.GetChildInnerText(node, "DarkGreen"));
            DarkGrey = XmlRel.GetHash(Xml.GetChildInnerText(node, "DarkGrey"));
            DarkOrange = XmlRel.GetHash(Xml.GetChildInnerText(node, "DarkOrange"));
            DarkPink = XmlRel.GetHash(Xml.GetChildInnerText(node, "DarkPink"));
            DarkRed = XmlRel.GetHash(Xml.GetChildInnerText(node, "DarkRed"));
            DarkSilver = XmlRel.GetHash(Xml.GetChildInnerText(node, "DarkSilver"));
            DarkWhite = XmlRel.GetHash(Xml.GetChildInnerText(node, "DarkWhite"));
            DarkYellow = XmlRel.GetHash(Xml.GetChildInnerText(node, "DarkYellow"));
            Unk53 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk53"));
            BeatUp = XmlRel.GetHash(Xml.GetChildInnerText(node, "BeatUp"));
            Unk55 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk55"));
            Custom = XmlRel.GetHash(Xml.GetChildInnerText(node, "Custom"));
            Unk57 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk57"));
            Unk58 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk58"));
            Unk59 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk59"));
            Dirty = XmlRel.GetHash(Xml.GetChildInnerText(node, "Dirty"));
            Unk61 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk61"));
            Mint = XmlRel.GetHash(Xml.GetChildInnerText(node, "Mint"));
            Unk63 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk63"));
            Unk64 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk64"));
            Unk65 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk65"));
            Rusty = XmlRel.GetHash(Xml.GetChildInnerText(node, "Rusty"));
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Black,Blue,Brown,Beige,Graphite,Green,Grey,Orange,Pink,Red,Silver,White,Yellow,
                MetallicBlack,MetallicBlue,MetallicBrown,MetallicBeige,MetallicGraphite,MetallicGreen,MetallicGrey,MetallicOrange,MetallicPink,MetallicRed,MetallicSilver,MetallicWhite,MetallicYellow,
                LightBlack,LightBlue,LightBrown,LightBeige,LightGraphite,LightGreen,LightGrey,LightOrange,LightPink,LightRed,LightSilver,LightWhite,LightYellow,
                DarkBlack,DarkBlue,DarkBrown,DarkBeige,DarkGraphite,DarkGreen,DarkGrey,DarkOrange,DarkPink,DarkRed,DarkSilver,DarkWhite,DarkYellow,
                Unk53,BeatUp,Unk55,Custom,Unk57,Unk58,Unk59,Dirty,Unk61,Mint,Unk63,Unk64,Unk65,Rusty };
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk77 : Dat151RelData
    {
        public MetaHash Unk01 { get; set; }//0
        public float Unk02 { get; set; }

        public Dat151Unk77(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk77;
            TypeID = (byte)Type;
        }
        public Dat151Unk77(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();//0
            Unk02 = br.ReadSingle();

            if (Unk01 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151MicrophoneItem : IMetaXmlItem
    {
        public float Unk01 { get; set; }
        public float Unk02 { get; set; }
        public float Unk03 { get; set; }
        public float Unk04 { get; set; }
        public float Unk05 { get; set; }
        public float Unk06 { get; set; }
        public int Unk07 { get; set; }
        public float Unk08 { get; set; }
        public float Unk09 { get; set; }

        public Dat151MicrophoneItem()
        { }
        public Dat151MicrophoneItem(BinaryReader br)
        {
            Unk01 = br.ReadSingle();
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadSingle();
            Unk07 = br.ReadInt32();
            Unk08 = br.ReadSingle();
            Unk09 = br.ReadSingle();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", FloatUtil.ToString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.ValueTag(sb, indent, "Unk08", FloatUtil.ToString(Unk08));
            RelXml.ValueTag(sb, indent, "Unk09", FloatUtil.ToString(Unk09));
        }
        public void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildFloatAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildIntAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildFloatAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildFloatAttribute(node, "Unk09", "value");
        }
        public override string ToString()
        {
            return string.Format("{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}", Unk01, Unk02, Unk03, Unk04, Unk05, Unk06, Unk07, Unk08, Unk09);
        }
    }
    [TC(typeof(EXP))] public class Dat151Microphone : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public byte Unk01 { get; set; }
        public byte ItemCount { get; set; }
        public byte Unk02 { get; set; }
        public byte Unk03 { get; set; }
        public Dat151MicrophoneItem[] Items { get; set; }

        public Dat151Microphone(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Microphone;
            TypeID = (byte)Type;
        }
        public Dat151Microphone(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Unk01 = br.ReadByte();
            ItemCount = br.ReadByte();
            Unk02 = br.ReadByte();
            Unk03 = br.ReadByte();

            Items = new Dat151MicrophoneItem[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151MicrophoneItem(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Unk01);
            bw.Write(ItemCount);
            bw.Write(Unk02);
            bw.Write(Unk03);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = (byte)Xml.GetChildIntAttribute(node, "Unk01", "value");
            Unk02 = (byte)Xml.GetChildIntAttribute(node, "Unk02", "value");
            Unk03 = (byte)Xml.GetChildIntAttribute(node, "Unk03", "value");
            Items = XmlRel.ReadItemArray<Dat151MicrophoneItem>(node, "Items");
            ItemCount = (byte)(Items?.Length ?? 0);
        }
    }
    [TC(typeof(EXP))] public class Dat151VehicleRecordItem : IMetaXmlItem
    {
        public float Time { get; set; }
        public MetaHash Hash1 { get; set; }
        public MetaHash Hash2 { get; set; }

        public Dat151VehicleRecordItem()
        { }
        public Dat151VehicleRecordItem(BinaryReader br)
        {
            Time = br.ReadSingle();
            Hash1 = br.ReadUInt32();
            Hash2 = br.ReadUInt32();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Time);
            bw.Write(Hash1);
            bw.Write(Hash2);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Time", FloatUtil.ToString(Time));
            RelXml.StringTag(sb, indent, "Hash1", RelXml.HashString(Hash1));
            RelXml.StringTag(sb, indent, "Hash2", RelXml.HashString(Hash2));
        }
        public void ReadXml(XmlNode node)
        {
            Time = Xml.GetChildFloatAttribute(node, "Time", "value");
            Hash1 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Hash1"));
            Hash2 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Hash2"));
        }
        public override string ToString()
        {
            return Time.ToString() + ", " + Hash1.ToString() + ", " + Hash2.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat151VehicleRecordItem2 : IMetaXmlItem
    {
        public MetaHash Unk01 { get; set; }
        public float Unk02 { get; set; }
        public float Unk03 { get; set; }

        public Dat151VehicleRecordItem2()
        { }
        public Dat151VehicleRecordItem2(BinaryReader br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadSingle();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
        }
        public void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
        }
        public override string ToString()
        {
            return Unk01.ToString() + ", " + Unk02.ToString() + ", " + Unk03.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat151VehicleRecord : Dat151RelData  //vehicle record audio? (YVR)
    {
        public MetaHash Unk01 { get; set; }
        public int Unk02 { get; set; }
        public int ItemCount { get; set; }
        public Dat151VehicleRecordItem[] Items { get; set; }
        public int ItemCount2 { get; set; }
        public Dat151VehicleRecordItem2[] Items2 { get; set; }

        public Dat151VehicleRecord(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.VehicleRecord;
            TypeID = (byte)Type;
        }
        public Dat151VehicleRecord(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadInt32();
            ItemCount = br.ReadInt32();
            Items = new Dat151VehicleRecordItem[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151VehicleRecordItem(br);
            }
            if (ItemCount != 0)
            {
                ItemCount2 = br.ReadInt32();
                Items2 = new Dat151VehicleRecordItem2[ItemCount2];
                for (int i = 0; i < ItemCount2; i++)
                {
                    Items2[i] = new Dat151VehicleRecordItem2(br);
                }
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
            if (ItemCount > 0)
            {
                bw.Write(ItemCount2);
                for (int i = 0; i < ItemCount2; i++)
                {
                    Items2[i].Write(bw);
                }
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.WriteItemArray(sb, Items, indent, "Items");
            if (ItemCount > 0)
            {
                RelXml.WriteItemArray(sb, Items2, indent, "Items2");
            }
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = Xml.GetChildIntAttribute(node, "Unk02", "value");
            Items = XmlRel.ReadItemArray<Dat151VehicleRecordItem>(node, "Items");
            ItemCount = (Items?.Length ?? 0);
            if (ItemCount > 0)
            {
                Items2 = XmlRel.ReadItemArray<Dat151VehicleRecordItem2>(node, "Items2");
                ItemCount2 = (Items2?.Length ?? 0);
            }
            else
            {
                Items2 = null;
                ItemCount2 = 0;
            }
        }
        public override MetaHash[] GetMixerHashes()
        {
            var list = new List<MetaHash>();
            list.Add(Unk01);
            if (Items != null)
            {
                foreach (var item in Items)
                {
                    list.Add(item.Hash2);
                }
            }
            if (Items2 != null)
            {
                foreach (var item in Items2)
                {
                    list.Add(item.Unk01);
                }
            }
            return list.ToArray();
        }
        public override MetaHash[] GetSoundHashes()
        {
            var list = new List<MetaHash>();
            if (Items != null)
            {
                foreach (var item in Items)
                {
                    list.Add(item.Hash1);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151AnimalFootstepsSounds : Dat151RelData
    {
        public MetaHash Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }
        public MetaHash Unk04 { get; set; }
        public MetaHash Unk05 { get; set; }
        public MetaHash Unk06 { get; set; }
        public MetaHash Unk07 { get; set; }
        public MetaHash Unk08 { get; set; }
        public MetaHash Unk09 { get; set; }
        public int Unk10 { get; set; }

        public Dat151AnimalFootstepsSounds(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.AnimalFootstepsSounds;
            TypeID = (byte)Type;
        }
        public Dat151AnimalFootstepsSounds(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadUInt32();
            Unk03 = br.ReadUInt32();
            Unk04 = br.ReadUInt32();
            Unk05 = br.ReadUInt32();
            Unk06 = br.ReadUInt32();
            Unk07 = br.ReadUInt32();
            Unk08 = br.ReadUInt32();
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = Xml.GetChildIntAttribute(node, "Unk10", "value");
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk01, Unk02, Unk03, Unk04, Unk05, Unk06, Unk07, Unk08, Unk09 };
        }
    }
    [TC(typeof(EXP))] public class Dat151Cloth : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public MetaHash Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }
        public MetaHash Unk04 { get; set; }
        public MetaHash Unk05 { get; set; }
        public MetaHash Unk06 { get; set; }
        public MetaHash Unk07 { get; set; }
        public MetaHash Unk08 { get; set; }//0
        public MetaHash Unk09 { get; set; }//another cloth...
        public MetaHash Unk10 { get; set; }
        public MetaHash Unk11 { get; set; }
        public MetaHash Unk12 { get; set; }//0
        public MetaHash Unk13 { get; set; }
        public MetaHash Unk14 { get; set; }

        public Dat151Cloth(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Cloth;
            TypeID = (byte)Type;
        }
        public Dat151Cloth(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadUInt32();
            Unk03 = br.ReadUInt32();
            Unk04 = br.ReadUInt32();
            Unk05 = br.ReadUInt32();
            Unk06 = br.ReadUInt32();
            Unk07 = br.ReadUInt32();
            Unk08 = br.ReadUInt32();//0
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadUInt32();
            Unk11 = br.ReadUInt32();
            Unk12 = br.ReadUInt32();//0
            Unk13 = br.ReadUInt32();
            Unk14 = br.ReadUInt32();

            if (Unk08 != 0)
            { }
            if (Unk12 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
            RelXml.StringTag(sb, indent, "Unk11", RelXml.HashString(Unk11));
            RelXml.StringTag(sb, indent, "Unk12", RelXml.HashString(Unk12));
            RelXml.StringTag(sb, indent, "Unk13", RelXml.HashString(Unk13));
            RelXml.StringTag(sb, indent, "Unk14", RelXml.HashString(Unk14));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
            Unk11 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk11"));
            Unk12 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk12"));
            Unk13 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk13"));
            Unk14 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk14"));
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk01, Unk02, Unk03, Unk04, Unk05, Unk06, Unk07, Unk10, Unk11, Unk13, Unk14 };
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { Unk09 };//is this necessary here?
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk95 : Dat151RelData
    {
        public MetaHash Unk01 { get; set; }
        public int Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }
        public float Unk04 { get; set; }

        public Dat151Unk95(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk95;
            TypeID = (byte)Type;
        }
        public Dat151Unk95(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadInt32();
            Unk03 = br.ReadUInt32();
            Unk04 = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = Xml.GetChildIntAttribute(node, "Unk02", "value");
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk01, Unk03 };
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk96Item : IMetaXmlItem
    {
        public MetaHash Unk01 { get; set; }//name eg. default, good_stealth, bad_stealth, soft_steps, drunk
        public float Unk02 { get; set; }
        public int Unk03 { get; set; }
        public int Unk04 { get; set; }
        public float Unk05 { get; set; }
        public float Unk06 { get; set; }
        public int Unk07 { get; set; }
        public MetaHash Unk08 { get; set; }//0
        public MetaHash Unk09 { get; set; }//??? not matching anything in dat.rel files
        public float Unk10 { get; set; }
        public int Unk11 { get; set; }
        public MetaHash Unk12 { get; set; }//0
        public MetaHash Unk13 { get; set; }//??? not matching anything in dat.rel files
        public float Unk14 { get; set; }
        public int Unk15 { get; set; }
        public MetaHash Unk16 { get; set; }//0
        public MetaHash Unk17 { get; set; }//??? not matching anything in dat.rel files
        public float Unk18 { get; set; }
        public int Unk19 { get; set; }
        public int Unk20 { get; set; }
        public MetaHash Unk21 { get; set; }//??? not matching anything in dat.rel files
        public float Unk22 { get; set; }
        public int Unk23 { get; set; }
        public MetaHash Unk24 { get; set; }//0
        public float Unk25 { get; set; }

        public Dat151Unk96Item()
        { }
        public Dat151Unk96Item(BinaryReader br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadInt32();
            Unk04 = br.ReadInt32();
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadSingle();
            Unk07 = br.ReadInt32();
            Unk08 = br.ReadUInt32();//0
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadSingle();
            Unk11 = br.ReadInt32();
            Unk12 = br.ReadUInt32();//0
            Unk13 = br.ReadUInt32();
            Unk14 = br.ReadSingle();
            Unk15 = br.ReadInt32();
            Unk16 = br.ReadUInt32();//0
            Unk17 = br.ReadUInt32();
            Unk18 = br.ReadSingle();
            Unk19 = br.ReadInt32();
            Unk20 = br.ReadInt32();
            Unk21 = br.ReadUInt32();
            Unk22 = br.ReadSingle();
            Unk23 = br.ReadInt32();
            Unk24 = br.ReadUInt32();//0
            Unk25 = br.ReadSingle();

            if (Unk08 != 0)
            { }
            if (Unk12 != 0)
            { }
            if (Unk16 != 0)
            { }
            if (Unk24 != 0)
            { }
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
            bw.Write(Unk19);
            bw.Write(Unk20);
            bw.Write(Unk21);
            bw.Write(Unk22);
            bw.Write(Unk23);
            bw.Write(Unk24);
            bw.Write(Unk25);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.ValueTag(sb, indent, "Unk10", FloatUtil.ToString(Unk10));
            RelXml.ValueTag(sb, indent, "Unk11", Unk11.ToString());
            RelXml.StringTag(sb, indent, "Unk12", RelXml.HashString(Unk12));
            RelXml.StringTag(sb, indent, "Unk13", RelXml.HashString(Unk13));
            RelXml.ValueTag(sb, indent, "Unk14", FloatUtil.ToString(Unk14));
            RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
            RelXml.StringTag(sb, indent, "Unk16", RelXml.HashString(Unk16));
            RelXml.StringTag(sb, indent, "Unk17", RelXml.HashString(Unk17));
            RelXml.ValueTag(sb, indent, "Unk18", FloatUtil.ToString(Unk18));
            RelXml.ValueTag(sb, indent, "Unk19", Unk19.ToString());
            RelXml.ValueTag(sb, indent, "Unk20", Unk20.ToString());
            RelXml.StringTag(sb, indent, "Unk21", RelXml.HashString(Unk21));
            RelXml.ValueTag(sb, indent, "Unk22", FloatUtil.ToString(Unk22));
            RelXml.ValueTag(sb, indent, "Unk23", Unk23.ToString());
            RelXml.StringTag(sb, indent, "Unk24", RelXml.HashString(Unk24));
            RelXml.ValueTag(sb, indent, "Unk25", FloatUtil.ToString(Unk25));
        }
        public void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildIntAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildIntAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildIntAttribute(node, "Unk07", "value");
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = Xml.GetChildFloatAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildIntAttribute(node, "Unk11", "value");
            Unk12 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk12"));
            Unk13 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk13"));
            Unk14 = Xml.GetChildFloatAttribute(node, "Unk14", "value");
            Unk15 = Xml.GetChildIntAttribute(node, "Unk15", "value");
            Unk16 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk16"));
            Unk17 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk17"));
            Unk18 = Xml.GetChildFloatAttribute(node, "Unk18", "value");
            Unk19 = Xml.GetChildIntAttribute(node, "Unk19", "value");
            Unk20 = Xml.GetChildIntAttribute(node, "Unk20", "value");
            Unk21 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk21"));
            Unk22 = Xml.GetChildFloatAttribute(node, "Unk22", "value");
            Unk23 = Xml.GetChildIntAttribute(node, "Unk23", "value");
            Unk24 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk24"));
            Unk25 = Xml.GetChildFloatAttribute(node, "Unk25", "value");
        }
        public override string ToString()
        {
            return Unk01.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk96 : Dat151RelData
    {
        public float Unk01 { get; set; }
        public float Unk02 { get; set; }
        public float Unk03 { get; set; }
        public float Unk04 { get; set; }
        public float Unk05 { get; set; }
        public int ItemCount { get; set; }
        public Dat151Unk96Item[] Items { get; set; }

        public Dat151Unk96(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk96;
            TypeID = (byte)Type;
        }
        public Dat151Unk96(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadSingle();
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadSingle();
            ItemCount = br.ReadInt32();
            Items = new Dat151Unk96Item[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151Unk96Item(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", FloatUtil.ToString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildFloatAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Items = XmlRel.ReadItemArray<Dat151Unk96Item>(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk99 : Dat151RelData
    {
        public float Unk01 { get; set; }

        public Dat151Unk99(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk99;
            TypeID = (byte)Type;
        }
        public Dat151Unk99(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", FloatUtil.ToString(Unk01));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildFloatAttribute(node, "Unk01", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151Tunnel : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public float Unk01 { get; set; }
        public float Unk02 { get; set; }
        public float Unk03 { get; set; }
        public float Unk04 { get; set; }
        public MetaHash Unk05 { get; set; }
        public MetaHash Unk06 { get; set; }
        public MetaHash Unk07 { get; set; }
        public float Unk08 { get; set; }
        public int Unk09 { get; set; }
        public float Unk10 { get; set; }
        public int Unk11 { get; set; }
        public float Unk12 { get; set; }
        public float Unk13 { get; set; }
        public float Unk14 { get; set; }
        public float Unk15 { get; set; }
        public float Unk16 { get; set; }
        public float Unk17 { get; set; }
        public MetaHash Unk18 { get; set; }//what is this?

        public Dat151Tunnel(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Tunnel;
            TypeID = (byte)Type;
        }
        public Dat151Tunnel(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Unk01 = br.ReadSingle();
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadUInt32();
            Unk06 = br.ReadUInt32();
            Unk07 = br.ReadUInt32();
            Unk08 = br.ReadSingle();
            Unk09 = br.ReadInt32();
            Unk10 = br.ReadSingle();
            Unk11 = br.ReadInt32();
            Unk12 = br.ReadSingle();
            Unk13 = br.ReadSingle();
            Unk14 = br.ReadSingle();
            Unk15 = br.ReadSingle();
            Unk16 = br.ReadSingle();
            Unk17 = br.ReadSingle();
            Unk18 = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", FloatUtil.ToString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.StringTag(sb, indent, "Unk07", RelXml.HashString(Unk07));
            RelXml.ValueTag(sb, indent, "Unk08", FloatUtil.ToString(Unk08));
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", FloatUtil.ToString(Unk10));
            RelXml.ValueTag(sb, indent, "Unk11", Unk11.ToString());
            RelXml.ValueTag(sb, indent, "Unk12", FloatUtil.ToString(Unk12));
            RelXml.ValueTag(sb, indent, "Unk13", FloatUtil.ToString(Unk13));
            RelXml.ValueTag(sb, indent, "Unk14", FloatUtil.ToString(Unk14));
            RelXml.ValueTag(sb, indent, "Unk15", FloatUtil.ToString(Unk15));
            RelXml.ValueTag(sb, indent, "Unk16", FloatUtil.ToString(Unk16));
            RelXml.ValueTag(sb, indent, "Unk17", FloatUtil.ToString(Unk17));
            RelXml.StringTag(sb, indent, "Unk18", RelXml.HashString(Unk18));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = Xml.GetChildFloatAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk07"));
            Unk08 = Xml.GetChildFloatAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildIntAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildFloatAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildIntAttribute(node, "Unk11", "value");
            Unk12 = Xml.GetChildFloatAttribute(node, "Unk12", "value");
            Unk13 = Xml.GetChildFloatAttribute(node, "Unk13", "value");
            Unk14 = Xml.GetChildFloatAttribute(node, "Unk14", "value");
            Unk15 = Xml.GetChildFloatAttribute(node, "Unk15", "value");
            Unk16 = Xml.GetChildFloatAttribute(node, "Unk16", "value");
            Unk17 = Xml.GetChildFloatAttribute(node, "Unk17", "value");
            Unk18 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk18"));
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk05, Unk06, Unk07 };
        }
    }
    [TC(typeof(EXP))] public class Dat151Alarm : Dat151RelData
    {
        public MetaHash DistantAlarm { get; set; }
        public MetaHash Curve { get; set; }
        public int Unk03 { get; set; }
        public MetaHash Interior { get; set; }//interior name: v_jewel2
        public MetaHash Alarm { get; set; }//alarm sound: script/alarm_bell_01
        public MetaHash Unk04 { get; set; }//0
        public MetaHash Unk05 { get; set; }//0
        public Vector3 Position { get; set; }
        public MetaHash Unk06 { get; set; }//0

        public Dat151Alarm(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Alarm;
            TypeID = (byte)Type;
        }
        public Dat151Alarm(RelData d, BinaryReader br) : base(d, br)
        {
            DistantAlarm = br.ReadUInt32();
            Curve = br.ReadUInt32();
            Unk03 = br.ReadInt32();
            Interior = br.ReadUInt32();//interior name: v_jewel2
            Alarm = br.ReadUInt32();//alarm sound: script/alarm_bell_01
            Unk04 = br.ReadUInt32();//0
            Unk05 = br.ReadUInt32();//0
            Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            Unk06 = br.ReadUInt32();//0

            if (Unk04 != 0)
            { }
            if (Unk05 != 0)
            { }
            if (Unk06 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(DistantAlarm);
            bw.Write(Curve);
            bw.Write(Unk03);
            bw.Write(Interior);
            bw.Write(Alarm);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Position.X);
            bw.Write(Position.Y);
            bw.Write(Position.Z);
            bw.Write(Unk06);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "DistantAlarm", RelXml.HashString(DistantAlarm));
            RelXml.StringTag(sb, indent, "Curve", RelXml.HashString(Curve));
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.StringTag(sb, indent, "Interior", RelXml.HashString(Interior));
            RelXml.StringTag(sb, indent, "Alarm", RelXml.HashString(Alarm));
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.SelfClosingTag(sb, indent, "Position " + FloatUtil.GetVector3XmlString(Position));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
        }
        public override void ReadXml(XmlNode node)
        {
            DistantAlarm = XmlRel.GetHash(Xml.GetChildInnerText(node, "DistantAlarm"));
            Curve = XmlRel.GetHash(Xml.GetChildInnerText(node, "Curve"));
            Unk03 = Xml.GetChildIntAttribute(node, "Unk03", "value");
            Interior = XmlRel.GetHash(Xml.GetChildInnerText(node, "Interior"));
            Alarm = XmlRel.GetHash(Xml.GetChildInnerText(node, "Alarm"));
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Position = Xml.GetChildVector3Attributes(node, "Position");
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { Curve };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { DistantAlarm };
        }
    }
    [TC(typeof(EXP))] public class Dat151SlowMoSettings : Dat151RelData
    {
        public MetaHash Unk01 { get; set; }
        public int Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }//0
        public MetaHash Unk04 { get; set; }

        public Dat151SlowMoSettings(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.SlowMoSettings;
            TypeID = (byte)Type;
        }
        public Dat151SlowMoSettings(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadInt32();
            Unk03 = br.ReadUInt32();//0
            Unk04 = br.ReadUInt32();

            if (Unk03 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = Xml.GetChildIntAttribute(node, "Unk02", "value");
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
        }
        public override MetaHash[] GetMixerHashes()
        {
            return new[] { Unk01 };
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk04 };
        }
    }
    [TC(typeof(EXP))] public class Dat151Scenario : Dat151RelData //eg world_human_musician
    {
        public FlagsUint Flags { get; set; }
        public int Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }
        public float Unk03 { get; set; }
        public int ItemCount { get; set; }
        public Dat151HashPair[] Items { get; set; }

        public Dat151Scenario(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Scenario;
            TypeID = (byte)Type;
        }
        public Dat151Scenario(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Unk01 = br.ReadInt32();
            Unk02 = br.ReadUInt32();
            Unk03 = br.ReadSingle();
            ItemCount = br.ReadInt32();
            Items = new Dat151HashPair[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151HashPair(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = Xml.GetChildIntAttribute(node, "Unk01", "value");
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Items = XmlRel.ReadItemArray<Dat151HashPair>(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
        public override MetaHash[] GetSoundHashes()
        {
            var list = new List<MetaHash>();
            list.Add(Unk02);
            if (Items != null)
            {
                foreach (var item in Items)
                {
                    list.Add(item.Hash1);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151AudioOcclusionOverride : Dat151RelData
    {
        //used in conjunction with the 'SET_PORTAL_SETTINGS_OVERRIDE'
        //and 'REMOVE_PORTAL_SETTINGS_OVERRIDE' natives to do real time changes to audio occlusion for interior portals.

        public float MaxOcclusion { get; set; } //value to override for a particular portal

        public Dat151AudioOcclusionOverride(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.AudioOcclusionOverride;
            TypeID = (byte)Type;
        }
        public Dat151AudioOcclusionOverride(RelData d, BinaryReader br) : base(d, br)
        {
            MaxOcclusion = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(MaxOcclusion);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "MaxOcclusion", FloatUtil.ToString(MaxOcclusion));
        }
        public override void ReadXml(XmlNode node)
        {
            MaxOcclusion = Xml.GetChildFloatAttribute(node, "MaxOcclusion", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151ElectricEngine : Dat151RelData
    {
        public int Unk01 { get; set; }
        public MetaHash Transmission { get; set; } //hybrid_tezeract_transmission
        public int Unk03 { get; set; }
        public int Unk04 { get; set; }
        public int Unk05 { get; set; }
        public MetaHash Turbo { get; set; } //hybrid_tezeract_turbo_whine
        public int Unk07 { get; set; }
        public int Unk08 { get; set; }
        public int Unk09 { get; set; }
        public int Unk10 { get; set; }
        public MetaHash RevsOff { get; set; } //streamed_vehicles_hybrid_hybrid_gas_revs_off
        public int Unk12 { get; set; }
        public int Unk13 { get; set; }
        public int Unk14 { get; set; }
        public MetaHash Unk15 { get; set; } //idle loop..?
        public MetaHash Start { get; set; } //streamed_vehicles_hybrid_voltic_start

        public Dat151ElectricEngine(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.ElectricEngine;
            TypeID = (byte)Type;
        }
        public Dat151ElectricEngine(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadInt32();
            Transmission = br.ReadUInt32();
            Unk03 = br.ReadInt32();
            Unk04 = br.ReadInt32();
            Unk05 = br.ReadInt32();
            Turbo = br.ReadUInt32();
            Unk07 = br.ReadInt32();
            Unk08 = br.ReadInt32();
            Unk09 = br.ReadInt32();
            Unk10 = br.ReadInt32();
            RevsOff = br.ReadUInt32();
            Unk12 = br.ReadInt32();
            Unk13 = br.ReadInt32();
            Unk14 = br.ReadInt32();
            Unk15 = br.ReadUInt32();
            Start = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Transmission);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Turbo);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(RevsOff);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Start);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.StringTag(sb, indent, "Transmission", RelXml.HashString(Transmission));
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.StringTag(sb, indent, "Turbo", RelXml.HashString(Turbo));
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.StringTag(sb, indent, "RevsOff", RelXml.HashString(RevsOff));
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.ToString());
            RelXml.ValueTag(sb, indent, "Unk13", Unk13.ToString());
            RelXml.ValueTag(sb, indent, "Unk14", Unk14.ToString());
            RelXml.StringTag(sb, indent, "Unk15", RelXml.HashString(Unk15));
            RelXml.StringTag(sb, indent, "Start", RelXml.HashString(Start));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildIntAttribute(node, "Unk01", "value");
            Transmission = XmlRel.GetHash(Xml.GetChildInnerText(node, "Transmission"));
            Unk03 = Xml.GetChildIntAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildIntAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildIntAttribute(node, "Unk05", "value");
            Turbo = XmlRel.GetHash(Xml.GetChildInnerText(node, "Turbo"));
            Unk07 = Xml.GetChildIntAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildIntAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildIntAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildIntAttribute(node, "Unk10", "value");
            RevsOff = XmlRel.GetHash(Xml.GetChildInnerText(node, "RevsOff"));
            Unk12 = Xml.GetChildIntAttribute(node, "Unk12", "value");
            Unk13 = Xml.GetChildIntAttribute(node, "Unk13", "value");
            Unk14 = Xml.GetChildIntAttribute(node, "Unk14", "value");
            Unk15 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk15"));
            Start = XmlRel.GetHash(Xml.GetChildInnerText(node, "Start"));
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Transmission, Turbo, RevsOff, Unk15, Start };
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk109 : Dat151RelData
    {
        public int Unk01 { get; set; }
        public int Unk02 { get; set; }
        public int Unk03 { get; set; }//0
        public int Unk04 { get; set; }
        public int Unk05 { get; set; }
        public int Unk06 { get; set; }
        public int Unk07 { get; set; }
        public int Unk08 { get; set; }
        public int Unk09 { get; set; }
        public int Unk10 { get; set; }
        public int Unk11 { get; set; }
        public int Unk12 { get; set; }
        public int Unk13 { get; set; }
        public int Unk14 { get; set; }
        public int Unk15 { get; set; }
        public int Unk16 { get; set; }
        public int Unk17 { get; set; }
        public int Unk18 { get; set; }

        public Dat151Unk109(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk109;
            TypeID = (byte)Type;
        }
        public Dat151Unk109(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadInt32();
            Unk02 = br.ReadInt32();
            Unk03 = br.ReadInt32();//0
            Unk04 = br.ReadInt32();
            Unk05 = br.ReadInt32();
            Unk06 = br.ReadInt32();
            Unk07 = br.ReadInt32();
            Unk08 = br.ReadInt32();
            Unk09 = br.ReadInt32();
            Unk10 = br.ReadInt32();
            Unk11 = br.ReadInt32();
            Unk12 = br.ReadInt32();
            Unk13 = br.ReadInt32();
            Unk14 = br.ReadInt32();
            Unk15 = br.ReadInt32();
            Unk16 = br.ReadInt32();
            Unk17 = br.ReadInt32();
            Unk18 = br.ReadInt32();

            if (Unk03 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.ValueTag(sb, indent, "Unk06", Unk06.ToString());
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.ValueTag(sb, indent, "Unk11", Unk11.ToString());
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.ToString());
            RelXml.ValueTag(sb, indent, "Unk13", Unk13.ToString());
            RelXml.ValueTag(sb, indent, "Unk14", Unk14.ToString());
            RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.ValueTag(sb, indent, "Unk17", Unk17.ToString());
            RelXml.ValueTag(sb, indent, "Unk18", Unk18.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildIntAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildIntAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildIntAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildIntAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildIntAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildIntAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildIntAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildIntAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildIntAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildIntAttribute(node, "Unk11", "value");
            Unk12 = Xml.GetChildIntAttribute(node, "Unk12", "value");
            Unk13 = Xml.GetChildIntAttribute(node, "Unk13", "value");
            Unk14 = Xml.GetChildIntAttribute(node, "Unk14", "value");
            Unk15 = Xml.GetChildIntAttribute(node, "Unk15", "value");
            Unk16 = Xml.GetChildIntAttribute(node, "Unk16", "value");
            Unk17 = Xml.GetChildIntAttribute(node, "Unk17", "value");
            Unk18 = Xml.GetChildIntAttribute(node, "Unk18", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk110Item : IMetaXmlItem
    {
        public string Name { get; set; } //eg AGREE_ACROSS_STREET
        public byte Unk1 { get; set; }// 1 or 255(-1?)

        public override string ToString()
        {
            return Name + ", " + Unk1.ToString();
        }

        public Dat151Unk110Item()
        {
        }
        public Dat151Unk110Item(BinaryReader br)
        {
            var data = br.ReadBytes(32);
            Name = Encoding.ASCII.GetString(data).Replace("\0", "");
            Unk1 = br.ReadByte();
        }
        public void Write(BinaryWriter bw)
        {
            var data = new byte[32];
            int len = Math.Min(Name?.Length ?? 0, 32);
            if (len > 0)
            {
                Encoding.ASCII.GetBytes(Name, 0, len, data, 0);
            }
            bw.Write(data);
            bw.Write(Unk1);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Name", Name.Replace("\n", "\\n"));//hacky escape
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
        }
        public void ReadXml(XmlNode node)
        {
            Name = Xml.GetChildInnerText(node, "Name").Replace("\\n", "\n");//hacky unescape
            Unk1 = (byte)Xml.GetChildUIntAttribute(node, "Unk1", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk110 : Dat151RelData //conversation/speech related - for scenarios?
    {
        public MetaHash Unk01 { get; set; }
        public short Unk02 { get; set; }
        public short Unk03 { get; set; }
        public float Unk04 { get; set; }
        public byte ItemCount { get; set; }
        public Dat151Unk110Item[] Items { get; set; }

        public Dat151Unk110(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk110;
            TypeID = (byte)Type;
        }
        public Dat151Unk110(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadInt16();
            Unk03 = br.ReadInt16();
            Unk04 = br.ReadSingle();
            ItemCount = br.ReadByte();
            Items = new Dat151Unk110Item[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151Unk110Item(br);
            }

            var brem = (4 - ((ItemCount + 1) % 4)) % 4;
            var pads = br.ReadBytes(brem); //read padding bytes
            foreach (var b in pads)
            {
                if (b != 0)
                { } //just make sure all pad bytes are 0..
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }

            var brem = (4 - ((ItemCount + 1) % 4)) % 4;
            for (int i = 0; i < brem; i++)
            {
                bw.Write((byte)0); //write padding bytes..
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = (short)Xml.GetChildIntAttribute(node, "Unk02", "value");
            Unk03 = (short)Xml.GetChildIntAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Items = XmlRel.ReadItemArray<Dat151Unk110Item>(node, "Items");
            ItemCount = (byte)(Items?.Length ?? 0);
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk01 };
        }
    }
    [TC(typeof(EXP))] public class Dat151AircraftWarningSettings : Dat151RelData
    {
        public int Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }//0
        public int Unk03 { get; set; }
        public int Unk04 { get; set; }
        public MetaHash Unk05 { get; set; }//0
        public int Unk06 { get; set; }
        public int Unk07 { get; set; }
        public MetaHash Unk08 { get; set; }//0
        public int Unk09 { get; set; }
        public int Unk10 { get; set; }
        public MetaHash Unk11 { get; set; }//0
        public int Unk12 { get; set; }
        public int Unk13 { get; set; }
        public MetaHash Unk14 { get; set; }//0
        public int Unk15 { get; set; }
        public int Unk16 { get; set; }
        public MetaHash Unk17 { get; set; }//0
        public int Unk18 { get; set; }
        public int Unk19 { get; set; }
        public MetaHash Unk20 { get; set; }//0
        public int Unk21 { get; set; }
        public int Unk22 { get; set; }
        public float Unk23 { get; set; }
        public MetaHash Unk24 { get; set; }//0
        public int Unk25 { get; set; }
        public int Unk26 { get; set; }
        public MetaHash Unk27 { get; set; }//0
        public int Unk28 { get; set; }
        public int Unk29 { get; set; }
        public MetaHash Unk30 { get; set; }//0
        public int Unk31 { get; set; }
        public int Unk32 { get; set; }
        public MetaHash Unk33 { get; set; }//0
        public int Unk34 { get; set; }
        public int Unk35 { get; set; }
        public MetaHash Unk36 { get; set; }//0
        public int Unk37 { get; set; }
        public int Unk38 { get; set; }
        public MetaHash Unk39 { get; set; }//0
        public int Unk40 { get; set; }
        public int Unk41 { get; set; }
        public MetaHash Unk42 { get; set; }//0
        public int Unk43 { get; set; }
        public int Unk44 { get; set; }
        public MetaHash Unk45 { get; set; }//0
        public int Unk46 { get; set; }
        public int Unk47 { get; set; }
        public MetaHash Unk48 { get; set; }//0
        public int Unk49 { get; set; }
        public int Unk50 { get; set; }
        public float Unk51 { get; set; }
        public MetaHash Unk52 { get; set; }//0
        public int Unk53 { get; set; }
        public int Unk54 { get; set; }
        public int Unk55 { get; set; }
        public MetaHash Unk56 { get; set; }//0
        public int Unk57 { get; set; }
        public int Unk58 { get; set; }


        public Dat151AircraftWarningSettings(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.AircraftWarningSettings;
            TypeID = (byte)Type;
        }
        public Dat151AircraftWarningSettings(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadInt32();
            Unk02 = br.ReadUInt32();//0
            Unk03 = br.ReadInt32();
            Unk04 = br.ReadInt32();
            Unk05 = br.ReadUInt32();//0
            Unk06 = br.ReadInt32();
            Unk07 = br.ReadInt32();
            Unk08 = br.ReadUInt32();//0
            Unk09 = br.ReadInt32();
            Unk10 = br.ReadInt32();
            Unk11 = br.ReadUInt32();//0
            Unk12 = br.ReadInt32();
            Unk13 = br.ReadInt32();
            Unk14 = br.ReadUInt32();//0
            Unk15 = br.ReadInt32();
            Unk16 = br.ReadInt32();
            Unk17 = br.ReadUInt32();//0
            Unk18 = br.ReadInt32();
            Unk19 = br.ReadInt32();
            Unk20 = br.ReadUInt32();//0
            Unk21 = br.ReadInt32();
            Unk22 = br.ReadInt32();
            Unk23 = br.ReadSingle();
            Unk24 = br.ReadUInt32();//0
            Unk25 = br.ReadInt32();
            Unk26 = br.ReadInt32();
            Unk27 = br.ReadUInt32();//0
            Unk28 = br.ReadInt32();
            Unk29 = br.ReadInt32();
            Unk30 = br.ReadUInt32();//0
            Unk31 = br.ReadInt32();
            Unk32 = br.ReadInt32();
            Unk33 = br.ReadUInt32();//0
            Unk34 = br.ReadInt32();
            Unk35 = br.ReadInt32();
            Unk36 = br.ReadUInt32();//0
            Unk37 = br.ReadInt32();
            Unk38 = br.ReadInt32();
            Unk39 = br.ReadUInt32();//0
            Unk40 = br.ReadInt32();
            Unk41 = br.ReadInt32();
            Unk42 = br.ReadUInt32();//0
            Unk43 = br.ReadInt32();
            Unk44 = br.ReadInt32();
            Unk45 = br.ReadUInt32();//0
            Unk46 = br.ReadInt32();
            Unk47 = br.ReadInt32();
            Unk48 = br.ReadUInt32();//0
            Unk49 = br.ReadInt32();
            Unk50 = br.ReadInt32();
            Unk51 = br.ReadSingle();
            Unk52 = br.ReadUInt32();//0
            Unk53 = br.ReadInt32();
            Unk54 = br.ReadInt32();
            Unk55 = br.ReadInt32();
            Unk56 = br.ReadUInt32();//0
            Unk57 = br.ReadInt32();
            Unk58 = br.ReadInt32();

            if (Unk02 != 0)
            { }
            if (Unk05 != 0)
            { }
            if (Unk08 != 0)
            { }
            if (Unk11 != 0)
            { }
            if (Unk14 != 0)
            { }
            if (Unk17 != 0)
            { }
            if (Unk20 != 0)
            { }
            if (Unk24 != 0)
            { }
            if (Unk27 != 0)
            { }
            if (Unk30 != 0)
            { }
            if (Unk33 != 0)
            { }
            if (Unk36 != 0)
            { }
            if (Unk39 != 0)
            { }
            if (Unk42 != 0)
            { }
            if (Unk45 != 0)
            { }
            if (Unk48 != 0)
            { }
            if (Unk52 != 0)
            { }
            if (Unk56 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
            bw.Write(Unk19);
            bw.Write(Unk20);
            bw.Write(Unk21);
            bw.Write(Unk22);
            bw.Write(Unk23);
            bw.Write(Unk24);
            bw.Write(Unk25);
            bw.Write(Unk26);
            bw.Write(Unk27);
            bw.Write(Unk28);
            bw.Write(Unk29);
            bw.Write(Unk30);
            bw.Write(Unk31);
            bw.Write(Unk32);
            bw.Write(Unk33);
            bw.Write(Unk34);
            bw.Write(Unk35);
            bw.Write(Unk36);
            bw.Write(Unk37);
            bw.Write(Unk38);
            bw.Write(Unk39);
            bw.Write(Unk40);
            bw.Write(Unk41);
            bw.Write(Unk42);
            bw.Write(Unk43);
            bw.Write(Unk44);
            bw.Write(Unk45);
            bw.Write(Unk46);
            bw.Write(Unk47);
            bw.Write(Unk48);
            bw.Write(Unk49);
            bw.Write(Unk50);
            bw.Write(Unk51);
            bw.Write(Unk52);
            bw.Write(Unk53);
            bw.Write(Unk54);
            bw.Write(Unk55);
            bw.Write(Unk56);
            bw.Write(Unk57);
            bw.Write(Unk58);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", Unk06.ToString());
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.StringTag(sb, indent, "Unk11", RelXml.HashString(Unk11));
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.ToString());
            RelXml.ValueTag(sb, indent, "Unk13", Unk13.ToString());
            RelXml.StringTag(sb, indent, "Unk14", RelXml.HashString(Unk14));
            RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.StringTag(sb, indent, "Unk17", RelXml.HashString(Unk17));
            RelXml.ValueTag(sb, indent, "Unk18", Unk18.ToString());
            RelXml.ValueTag(sb, indent, "Unk19", Unk19.ToString());
            RelXml.StringTag(sb, indent, "Unk20", RelXml.HashString(Unk20));
            RelXml.ValueTag(sb, indent, "Unk21", Unk21.ToString());
            RelXml.ValueTag(sb, indent, "Unk22", Unk22.ToString());
            RelXml.ValueTag(sb, indent, "Unk23", FloatUtil.ToString(Unk23));
            RelXml.StringTag(sb, indent, "Unk24", RelXml.HashString(Unk24));
            RelXml.ValueTag(sb, indent, "Unk25", Unk25.ToString());
            RelXml.ValueTag(sb, indent, "Unk26", Unk26.ToString());
            RelXml.StringTag(sb, indent, "Unk27", RelXml.HashString(Unk27));
            RelXml.ValueTag(sb, indent, "Unk28", Unk28.ToString());
            RelXml.ValueTag(sb, indent, "Unk29", Unk29.ToString());
            RelXml.StringTag(sb, indent, "Unk30", RelXml.HashString(Unk30));
            RelXml.ValueTag(sb, indent, "Unk31", Unk31.ToString());
            RelXml.ValueTag(sb, indent, "Unk32", Unk32.ToString());
            RelXml.StringTag(sb, indent, "Unk33", RelXml.HashString(Unk33));
            RelXml.ValueTag(sb, indent, "Unk34", Unk34.ToString());
            RelXml.ValueTag(sb, indent, "Unk35", Unk35.ToString());
            RelXml.StringTag(sb, indent, "Unk36", RelXml.HashString(Unk36));
            RelXml.ValueTag(sb, indent, "Unk37", Unk37.ToString());
            RelXml.ValueTag(sb, indent, "Unk38", Unk38.ToString());
            RelXml.StringTag(sb, indent, "Unk39", RelXml.HashString(Unk39));
            RelXml.ValueTag(sb, indent, "Unk40", Unk40.ToString());
            RelXml.ValueTag(sb, indent, "Unk41", Unk41.ToString());
            RelXml.StringTag(sb, indent, "Unk42", RelXml.HashString(Unk42));
            RelXml.ValueTag(sb, indent, "Unk43", Unk43.ToString());
            RelXml.ValueTag(sb, indent, "Unk44", Unk44.ToString());
            RelXml.StringTag(sb, indent, "Unk45", RelXml.HashString(Unk45));
            RelXml.ValueTag(sb, indent, "Unk46", Unk46.ToString());
            RelXml.ValueTag(sb, indent, "Unk47", Unk47.ToString());
            RelXml.StringTag(sb, indent, "Unk48", RelXml.HashString(Unk48));
            RelXml.ValueTag(sb, indent, "Unk49", Unk49.ToString());
            RelXml.ValueTag(sb, indent, "Unk50", Unk50.ToString());
            RelXml.ValueTag(sb, indent, "Unk51", FloatUtil.ToString(Unk51));
            RelXml.StringTag(sb, indent, "Unk52", RelXml.HashString(Unk52));
            RelXml.ValueTag(sb, indent, "Unk53", Unk53.ToString());
            RelXml.ValueTag(sb, indent, "Unk54", Unk54.ToString());
            RelXml.ValueTag(sb, indent, "Unk55", Unk55.ToString());
            RelXml.StringTag(sb, indent, "Unk56", RelXml.HashString(Unk56));
            RelXml.ValueTag(sb, indent, "Unk57", Unk57.ToString());
            RelXml.ValueTag(sb, indent, "Unk58", Unk58.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildIntAttribute(node, "Unk01", "value");
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = Xml.GetChildIntAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildIntAttribute(node, "Unk04", "value");
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = Xml.GetChildIntAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildIntAttribute(node, "Unk07", "value");
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = Xml.GetChildIntAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildIntAttribute(node, "Unk10", "value");
            Unk11 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk11"));
            Unk12 = Xml.GetChildIntAttribute(node, "Unk12", "value");
            Unk13 = Xml.GetChildIntAttribute(node, "Unk13", "value");
            Unk14 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk14"));
            Unk15 = Xml.GetChildIntAttribute(node, "Unk15", "value");
            Unk16 = Xml.GetChildIntAttribute(node, "Unk16", "value");
            Unk17 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk17"));
            Unk18 = Xml.GetChildIntAttribute(node, "Unk18", "value");
            Unk19 = Xml.GetChildIntAttribute(node, "Unk19", "value");
            Unk20 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk20"));
            Unk21 = Xml.GetChildIntAttribute(node, "Unk21", "value");
            Unk22 = Xml.GetChildIntAttribute(node, "Unk22", "value");
            Unk23 = Xml.GetChildFloatAttribute(node, "Unk23", "value");
            Unk24 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk24"));
            Unk25 = Xml.GetChildIntAttribute(node, "Unk25", "value");
            Unk26 = Xml.GetChildIntAttribute(node, "Unk26", "value");
            Unk27 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk27"));
            Unk28 = Xml.GetChildIntAttribute(node, "Unk28", "value");
            Unk29 = Xml.GetChildIntAttribute(node, "Unk29", "value");
            Unk30 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk30"));
            Unk31 = Xml.GetChildIntAttribute(node, "Unk31", "value");
            Unk32 = Xml.GetChildIntAttribute(node, "Unk32", "value");
            Unk33 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk33"));
            Unk34 = Xml.GetChildIntAttribute(node, "Unk34", "value");
            Unk35 = Xml.GetChildIntAttribute(node, "Unk35", "value");
            Unk36 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk36"));
            Unk37 = Xml.GetChildIntAttribute(node, "Unk37", "value");
            Unk38 = Xml.GetChildIntAttribute(node, "Unk38", "value");
            Unk39 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk39"));
            Unk40 = Xml.GetChildIntAttribute(node, "Unk40", "value");
            Unk41 = Xml.GetChildIntAttribute(node, "Unk41", "value");
            Unk42 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk42"));
            Unk43 = Xml.GetChildIntAttribute(node, "Unk43", "value");
            Unk44 = Xml.GetChildIntAttribute(node, "Unk44", "value");
            Unk45 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk45"));
            Unk46 = Xml.GetChildIntAttribute(node, "Unk46", "value");
            Unk47 = Xml.GetChildIntAttribute(node, "Unk47", "value");
            Unk48 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk48"));
            Unk49 = Xml.GetChildIntAttribute(node, "Unk49", "value");
            Unk50 = Xml.GetChildIntAttribute(node, "Unk50", "value");
            Unk51 = Xml.GetChildFloatAttribute(node, "Unk51", "value");
            Unk52 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk52"));
            Unk53 = Xml.GetChildIntAttribute(node, "Unk53", "value");
            Unk54 = Xml.GetChildIntAttribute(node, "Unk54", "value");
            Unk55 = Xml.GetChildIntAttribute(node, "Unk55", "value");
            Unk56 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk56"));
            Unk57 = Xml.GetChildIntAttribute(node, "Unk57", "value");
            Unk58 = Xml.GetChildIntAttribute(node, "Unk58", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk112Item : IMetaXmlItem
    {
        public MetaHash Unk01 { get; set; }
        public float Unk02 { get; set; }
        public float Unk03 { get; set; }
        public byte Unk04 { get; set; }
        public byte Unk05 { get; set; }
        public short Unk06 { get; set; }

        public Dat151Unk112Item()
        { }
        public Dat151Unk112Item(BinaryReader br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadByte();
            Unk05 = br.ReadByte();
            Unk06 = br.ReadInt16();

            if (Unk06 != 0)
            { }
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.ValueTag(sb, indent, "Unk06", Unk06.ToString());
        }
        public void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = (byte)Xml.GetChildUIntAttribute(node, "Unk04", "value");
            Unk05 = (byte)Xml.GetChildUIntAttribute(node, "Unk05", "value");
            Unk06 = (short)Xml.GetChildIntAttribute(node, "Unk06", "value");
        }
        public override string ToString()
        {
            return Unk01.ToString() + ": " + Unk02.ToString() + ", " + Unk03.ToString() + ", " + Unk04.ToString() + ", " + Unk05.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk112 : Dat151RelData
    {
        public int ItemCount { get; set; }
        public Dat151Unk112Item[] Items { get; set; }

        public Dat151Unk112(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk112;
            TypeID = (byte)Type;
        }
        public Dat151Unk112(RelData d, BinaryReader br) : base(d, br)
        {
            ItemCount = br.ReadInt32();
            Items = new Dat151Unk112Item[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151Unk112Item(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Items = XmlRel.ReadItemArray<Dat151Unk112Item>(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            if (Items != null)
            {
                foreach (var item in Items)
                {
                    list.Add(item.Unk01);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151CopDispatchInteractionSettings : Dat151RelData
    {
        public int Unk01 { get; set; }
        public int Unk02 { get; set; }
        public int Unk03 { get; set; }
        public int Unk04 { get; set; }
        public int Unk05 { get; set; }
        public int Unk06 { get; set; }
        public int Unk07 { get; set; }
        public int Unk08 { get; set; }
        public int Unk09 { get; set; }
        public int Unk10 { get; set; }
        public int Unk11 { get; set; }
        public int Unk12 { get; set; }
        public int Unk13 { get; set; }
        public int Unk14 { get; set; }
        public int Unk15 { get; set; }
        public int Unk16 { get; set; }
        public int Unk17 { get; set; }
        public int Unk18 { get; set; }
        public int Unk19 { get; set; }
        public int Unk20 { get; set; }
        public int Unk21 { get; set; }
        public int Unk22 { get; set; }
        public int Unk23 { get; set; }
        public int Unk24 { get; set; }
        public int Unk25 { get; set; }
        public int Unk26 { get; set; }
        public int Unk27 { get; set; }
        public int Unk28 { get; set; }
        public int Unk29 { get; set; }
        public int Unk30 { get; set; }
        public int Unk31 { get; set; }
        public float Unk32 { get; set; }
        public int Unk33 { get; set; }
        public int Unk34 { get; set; }
        public int Unk35 { get; set; }
        public float Unk36 { get; set; }
        public int Unk37 { get; set; }
        public int Unk38 { get; set; }
        public int Unk39 { get; set; }
        public int Unk40 { get; set; }
        public int Unk41 { get; set; }
        public int Unk42 { get; set; }

        public Dat151CopDispatchInteractionSettings(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.CopDispatchInteractionSettings;
            TypeID = (byte)Type;
        }
        public Dat151CopDispatchInteractionSettings(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadInt32();
            Unk02 = br.ReadInt32();
            Unk03 = br.ReadInt32();
            Unk04 = br.ReadInt32();
            Unk05 = br.ReadInt32();
            Unk06 = br.ReadInt32();
            Unk07 = br.ReadInt32();
            Unk08 = br.ReadInt32();
            Unk09 = br.ReadInt32();
            Unk10 = br.ReadInt32();
            Unk11 = br.ReadInt32();
            Unk12 = br.ReadInt32();
            Unk13 = br.ReadInt32();
            Unk14 = br.ReadInt32();
            Unk15 = br.ReadInt32();
            Unk16 = br.ReadInt32();
            Unk17 = br.ReadInt32();
            Unk18 = br.ReadInt32();
            Unk19 = br.ReadInt32();
            Unk20 = br.ReadInt32();
            Unk21 = br.ReadInt32();
            Unk22 = br.ReadInt32();
            Unk23 = br.ReadInt32();
            Unk24 = br.ReadInt32();
            Unk25 = br.ReadInt32();
            Unk26 = br.ReadInt32();
            Unk27 = br.ReadInt32();
            Unk28 = br.ReadInt32();
            Unk29 = br.ReadInt32();
            Unk30 = br.ReadInt32();
            Unk31 = br.ReadInt32();
            Unk32 = br.ReadSingle();
            Unk33 = br.ReadInt32();
            Unk34 = br.ReadInt32();
            Unk35 = br.ReadInt32();
            Unk36 = br.ReadSingle();
            Unk37 = br.ReadInt32();
            Unk38 = br.ReadInt32();
            Unk39 = br.ReadInt32();
            Unk40 = br.ReadInt32();
            Unk41 = br.ReadInt32();
            Unk42 = br.ReadInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
            bw.Write(Unk19);
            bw.Write(Unk20);
            bw.Write(Unk21);
            bw.Write(Unk22);
            bw.Write(Unk23);
            bw.Write(Unk24);
            bw.Write(Unk25);
            bw.Write(Unk26);
            bw.Write(Unk27);
            bw.Write(Unk28);
            bw.Write(Unk29);
            bw.Write(Unk30);
            bw.Write(Unk31);
            bw.Write(Unk32);
            bw.Write(Unk33);
            bw.Write(Unk34);
            bw.Write(Unk35);
            bw.Write(Unk36);
            bw.Write(Unk37);
            bw.Write(Unk38);
            bw.Write(Unk39);
            bw.Write(Unk40);
            bw.Write(Unk41);
            bw.Write(Unk42);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.ValueTag(sb, indent, "Unk06", Unk06.ToString());
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.ValueTag(sb, indent, "Unk11", Unk11.ToString());
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.ToString());
            RelXml.ValueTag(sb, indent, "Unk13", Unk13.ToString());
            RelXml.ValueTag(sb, indent, "Unk14", Unk14.ToString());
            RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.ValueTag(sb, indent, "Unk17", Unk17.ToString());
            RelXml.ValueTag(sb, indent, "Unk18", Unk18.ToString());
            RelXml.ValueTag(sb, indent, "Unk19", Unk19.ToString());
            RelXml.ValueTag(sb, indent, "Unk20", Unk20.ToString());
            RelXml.ValueTag(sb, indent, "Unk21", Unk21.ToString());
            RelXml.ValueTag(sb, indent, "Unk22", Unk22.ToString());
            RelXml.ValueTag(sb, indent, "Unk23", Unk23.ToString());
            RelXml.ValueTag(sb, indent, "Unk24", Unk24.ToString());
            RelXml.ValueTag(sb, indent, "Unk25", Unk25.ToString());
            RelXml.ValueTag(sb, indent, "Unk26", Unk26.ToString());
            RelXml.ValueTag(sb, indent, "Unk27", Unk27.ToString());
            RelXml.ValueTag(sb, indent, "Unk28", Unk28.ToString());
            RelXml.ValueTag(sb, indent, "Unk29", Unk29.ToString());
            RelXml.ValueTag(sb, indent, "Unk30", Unk30.ToString());
            RelXml.ValueTag(sb, indent, "Unk31", Unk31.ToString());
            RelXml.ValueTag(sb, indent, "Unk32", FloatUtil.ToString(Unk32));
            RelXml.ValueTag(sb, indent, "Unk33", Unk33.ToString());
            RelXml.ValueTag(sb, indent, "Unk34", Unk34.ToString());
            RelXml.ValueTag(sb, indent, "Unk35", Unk35.ToString());
            RelXml.ValueTag(sb, indent, "Unk36", FloatUtil.ToString(Unk36));
            RelXml.ValueTag(sb, indent, "Unk37", Unk37.ToString());
            RelXml.ValueTag(sb, indent, "Unk38", Unk38.ToString());
            RelXml.ValueTag(sb, indent, "Unk39", Unk39.ToString());
            RelXml.ValueTag(sb, indent, "Unk40", Unk40.ToString());
            RelXml.ValueTag(sb, indent, "Unk41", Unk41.ToString());
            RelXml.ValueTag(sb, indent, "Unk42", Unk42.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildIntAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildIntAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildIntAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildIntAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildIntAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildIntAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildIntAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildIntAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildIntAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildIntAttribute(node, "Unk11", "value");
            Unk12 = Xml.GetChildIntAttribute(node, "Unk12", "value");
            Unk13 = Xml.GetChildIntAttribute(node, "Unk13", "value");
            Unk14 = Xml.GetChildIntAttribute(node, "Unk14", "value");
            Unk15 = Xml.GetChildIntAttribute(node, "Unk15", "value");
            Unk16 = Xml.GetChildIntAttribute(node, "Unk16", "value");
            Unk17 = Xml.GetChildIntAttribute(node, "Unk17", "value");
            Unk18 = Xml.GetChildIntAttribute(node, "Unk18", "value");
            Unk19 = Xml.GetChildIntAttribute(node, "Unk19", "value");
            Unk20 = Xml.GetChildIntAttribute(node, "Unk20", "value");
            Unk21 = Xml.GetChildIntAttribute(node, "Unk21", "value");
            Unk22 = Xml.GetChildIntAttribute(node, "Unk22", "value");
            Unk23 = Xml.GetChildIntAttribute(node, "Unk23", "value");
            Unk24 = Xml.GetChildIntAttribute(node, "Unk24", "value");
            Unk25 = Xml.GetChildIntAttribute(node, "Unk25", "value");
            Unk26 = Xml.GetChildIntAttribute(node, "Unk26", "value");
            Unk27 = Xml.GetChildIntAttribute(node, "Unk27", "value");
            Unk28 = Xml.GetChildIntAttribute(node, "Unk28", "value");
            Unk29 = Xml.GetChildIntAttribute(node, "Unk29", "value");
            Unk30 = Xml.GetChildIntAttribute(node, "Unk30", "value");
            Unk31 = Xml.GetChildIntAttribute(node, "Unk31", "value");
            Unk32 = Xml.GetChildFloatAttribute(node, "Unk32", "value");
            Unk33 = Xml.GetChildIntAttribute(node, "Unk33", "value");
            Unk34 = Xml.GetChildIntAttribute(node, "Unk34", "value");
            Unk35 = Xml.GetChildIntAttribute(node, "Unk35", "value");
            Unk36 = Xml.GetChildFloatAttribute(node, "Unk36", "value");
            Unk37 = Xml.GetChildIntAttribute(node, "Unk37", "value");
            Unk38 = Xml.GetChildIntAttribute(node, "Unk38", "value");
            Unk39 = Xml.GetChildIntAttribute(node, "Unk39", "value");
            Unk40 = Xml.GetChildIntAttribute(node, "Unk40", "value");
            Unk41 = Xml.GetChildIntAttribute(node, "Unk41", "value");
            Unk42 = Xml.GetChildIntAttribute(node, "Unk42", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk115 : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public float Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }//static emitter
        public float Unk03 { get; set; }
        public float Unk04 { get; set; }
        public float Unk05 { get; set; }
        public float Unk06 { get; set; }
        public int Unk07 { get; set; }
        public int Unk08 { get; set; }
        public MetaHash Unk09 { get; set; }//static emitter
        public float Unk10 { get; set; }
        public float Unk11 { get; set; }
        public int Unk12 { get; set; }
        public int Unk13 { get; set; }
        public int Unk14 { get; set; }
        public int Unk15 { get; set; }
        public int Unk16 { get; set; }
        public int Unk17 { get; set; }
        public float Unk18 { get; set; }
        public float Unk19 { get; set; }
        public int Unk20 { get; set; }
        public int Unk21 { get; set; }

        public Dat151Unk115(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk115;
            TypeID = (byte)Type;
        }
        public Dat151Unk115(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            Unk01 = br.ReadSingle();
            Unk02 = br.ReadUInt32();
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadSingle();
            Unk07 = br.ReadInt32();
            Unk08 = br.ReadInt32();
            Unk09 = br.ReadUInt32();
            Unk10 = br.ReadSingle();
            Unk11 = br.ReadSingle();
            Unk12 = br.ReadInt32();
            Unk13 = br.ReadInt32();
            Unk14 = br.ReadInt32();
            Unk15 = br.ReadInt32();
            Unk16 = br.ReadInt32();
            Unk17 = br.ReadInt32();
            Unk18 = br.ReadSingle();
            Unk19 = br.ReadSingle();
            Unk20 = br.ReadInt32();
            Unk21 = br.ReadInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
            bw.Write(Unk19);
            bw.Write(Unk20);
            bw.Write(Unk21);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", FloatUtil.ToString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", Unk07.ToString());
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.ValueTag(sb, indent, "Unk10", FloatUtil.ToString(Unk10));
            RelXml.ValueTag(sb, indent, "Unk11", FloatUtil.ToString(Unk11));
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.ToString());
            RelXml.ValueTag(sb, indent, "Unk13", Unk13.ToString());
            RelXml.ValueTag(sb, indent, "Unk14", Unk14.ToString());
            RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.ValueTag(sb, indent, "Unk17", Unk17.ToString());
            RelXml.ValueTag(sb, indent, "Unk18", FloatUtil.ToString(Unk18));
            RelXml.ValueTag(sb, indent, "Unk19", FloatUtil.ToString(Unk19));
            RelXml.ValueTag(sb, indent, "Unk20", Unk20.ToString());
            RelXml.ValueTag(sb, indent, "Unk21", Unk21.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = Xml.GetChildFloatAttribute(node, "Unk01", "value");
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildIntAttribute(node, "Unk07", "value");
            Unk08 = Xml.GetChildIntAttribute(node, "Unk08", "value");
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = Xml.GetChildFloatAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildFloatAttribute(node, "Unk11", "value");
            Unk12 = Xml.GetChildIntAttribute(node, "Unk12", "value");
            Unk13 = Xml.GetChildIntAttribute(node, "Unk13", "value");
            Unk14 = Xml.GetChildIntAttribute(node, "Unk14", "value");
            Unk15 = Xml.GetChildIntAttribute(node, "Unk15", "value");
            Unk16 = Xml.GetChildIntAttribute(node, "Unk16", "value");
            Unk17 = Xml.GetChildIntAttribute(node, "Unk17", "value");
            Unk18 = Xml.GetChildFloatAttribute(node, "Unk18", "value");
            Unk19 = Xml.GetChildFloatAttribute(node, "Unk19", "value");
            Unk20 = Xml.GetChildIntAttribute(node, "Unk20", "value");
            Unk21 = Xml.GetChildIntAttribute(node, "Unk21", "value");
        }
        public override MetaHash[] GetGameHashes()
        {
            return new[] { Unk02, Unk09 };
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk116 : Dat151RelData //tennis_vfx_settings
    {
        public MetaHash Unk01 { get; set; }//0
        public float Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }//0
        public MetaHash Unk04 { get; set; }//0
        public MetaHash Unk05 { get; set; }//0
        public MetaHash Unk06 { get; set; }//0
        public float Unk07 { get; set; }
        public MetaHash Unk08 { get; set; }//0
        public MetaHash Unk09 { get; set; }//0
        public MetaHash Unk10 { get; set; }//0
        public MetaHash Unk11 { get; set; }//0
        public float Unk12 { get; set; }

        public Dat151Unk116(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk116;
            TypeID = (byte)Type;
        }
        public Dat151Unk116(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();//0
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadUInt32();//0
            Unk04 = br.ReadUInt32();//0
            Unk05 = br.ReadUInt32();//0
            Unk06 = br.ReadUInt32();//0
            Unk07 = br.ReadSingle();
            Unk08 = br.ReadUInt32();//0
            Unk09 = br.ReadUInt32();//0
            Unk10 = br.ReadUInt32();//0
            Unk11 = br.ReadUInt32();//0
            Unk12 = br.ReadSingle();

            if (Unk01 != 0)
            { }
            if (Unk03 != 0)
            { }
            if (Unk04 != 0)
            { }
            if (Unk05 != 0)
            { }
            if (Unk06 != 0)
            { }
            if (Unk08 != 0)
            { }
            if (Unk09 != 0)
            { }
            if (Unk10 != 0)
            { }
            if (Unk11 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
            RelXml.StringTag(sb, indent, "Unk05", RelXml.HashString(Unk05));
            RelXml.StringTag(sb, indent, "Unk06", RelXml.HashString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", FloatUtil.ToString(Unk07));
            RelXml.StringTag(sb, indent, "Unk08", RelXml.HashString(Unk08));
            RelXml.StringTag(sb, indent, "Unk09", RelXml.HashString(Unk09));
            RelXml.StringTag(sb, indent, "Unk10", RelXml.HashString(Unk10));
            RelXml.StringTag(sb, indent, "Unk11", RelXml.HashString(Unk11));
            RelXml.ValueTag(sb, indent, "Unk12", FloatUtil.ToString(Unk12));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
            Unk05 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk05"));
            Unk06 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk06"));
            Unk07 = Xml.GetChildFloatAttribute(node, "Unk07", "value");
            Unk08 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk08"));
            Unk09 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk09"));
            Unk10 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk10"));
            Unk11 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk11"));
            Unk12 = Xml.GetChildFloatAttribute(node, "Unk12", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk118 : Dat151RelData
    {
        public int Unk01 { get; set; }
        public int Unk02 { get; set; }
        public float Unk03 { get; set; }
        public int Unk04 { get; set; }
        public int Unk05 { get; set; }
        public float Unk06 { get; set; }
        public float Unk07 { get; set; }
        public short Unk08 { get; set; }
        public short Unk09 { get; set; }
        public float Unk10 { get; set; }
        public float Unk11 { get; set; }
        public int Unk12 { get; set; }
        public int Unk13 { get; set; }
        public float Unk14 { get; set; }
        public float Unk15 { get; set; }
        public int Unk16 { get; set; }
        public int Unk17 { get; set; }
        public float Unk18 { get; set; }
        public int Unk19 { get; set; }
        public float Unk20 { get; set; }

        public Dat151Unk118(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk118;
            TypeID = (byte)Type;
        }
        public Dat151Unk118(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadInt32();
            Unk02 = br.ReadInt32();
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadInt32();
            Unk05 = br.ReadInt32();
            Unk06 = br.ReadSingle();
            Unk07 = br.ReadSingle();
            Unk08 = br.ReadInt16();
            Unk09 = br.ReadInt16();
            Unk10 = br.ReadSingle();
            Unk11 = br.ReadSingle();
            Unk12 = br.ReadInt32();
            Unk13 = br.ReadInt32();
            Unk14 = br.ReadSingle();
            Unk15 = br.ReadSingle();
            Unk16 = br.ReadInt32();
            Unk17 = br.ReadInt32();
            Unk18 = br.ReadSingle();
            Unk19 = br.ReadInt32();
            Unk20 = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
            bw.Write(Unk07);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
            bw.Write(Unk19);
            bw.Write(Unk20);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", Unk02.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", Unk04.ToString());
            RelXml.ValueTag(sb, indent, "Unk05", Unk05.ToString());
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
            RelXml.ValueTag(sb, indent, "Unk07", FloatUtil.ToString(Unk07));
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", FloatUtil.ToString(Unk10));
            RelXml.ValueTag(sb, indent, "Unk11", FloatUtil.ToString(Unk11));
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.ToString());
            RelXml.ValueTag(sb, indent, "Unk13", Unk13.ToString());
            RelXml.ValueTag(sb, indent, "Unk14", FloatUtil.ToString(Unk14));
            RelXml.ValueTag(sb, indent, "Unk15", FloatUtil.ToString(Unk15));
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.ValueTag(sb, indent, "Unk17", Unk17.ToString());
            RelXml.ValueTag(sb, indent, "Unk18", FloatUtil.ToString(Unk18));
            RelXml.ValueTag(sb, indent, "Unk19", Unk19.ToString());
            RelXml.ValueTag(sb, indent, "Unk20", FloatUtil.ToString(Unk20));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = Xml.GetChildIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildIntAttribute(node, "Unk02", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildIntAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildIntAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
            Unk07 = Xml.GetChildFloatAttribute(node, "Unk07", "value");
            Unk08 = (short)Xml.GetChildIntAttribute(node, "Unk08", "value");
            Unk09 = (short)Xml.GetChildIntAttribute(node, "Unk09", "value");
            Unk10 = Xml.GetChildFloatAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildFloatAttribute(node, "Unk11", "value");
            Unk12 = Xml.GetChildIntAttribute(node, "Unk12", "value");
            Unk13 = Xml.GetChildIntAttribute(node, "Unk13", "value");
            Unk14 = Xml.GetChildFloatAttribute(node, "Unk14", "value");
            Unk15 = Xml.GetChildFloatAttribute(node, "Unk15", "value");
            Unk16 = Xml.GetChildIntAttribute(node, "Unk16", "value");
            Unk17 = Xml.GetChildIntAttribute(node, "Unk17", "value");
            Unk18 = Xml.GetChildFloatAttribute(node, "Unk18", "value");
            Unk19 = Xml.GetChildIntAttribute(node, "Unk19", "value");
            Unk20 = Xml.GetChildFloatAttribute(node, "Unk20", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat151Unk119 : Dat151RelData //prop_bush_lrg_02
    {
        public MetaHash Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }

        public Dat151Unk119(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.Unk119;
            TypeID = (byte)Type;
        }
        public Dat151Unk119(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadUInt32();
            Unk03 = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
        }
        public override void ReadXml(XmlNode node)
        {
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk01, Unk02, Unk03 };
        }
    }
    [TC(typeof(EXP))] public class Dat151MacsModelsOverrides : Dat151RelData //macs_models_overrides
    {
        public int ItemCount { get; set; }
        public Dat151HashPair[] Items { get; set; }

        public Dat151MacsModelsOverrides(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.MacsModelsOverrides;
            TypeID = (byte)Type;
        }
        public Dat151MacsModelsOverrides(RelData d, BinaryReader br) : base(d, br)
        {
            ItemCount = br.ReadInt32();
            Items = new Dat151HashPair[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151HashPair(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffset(bw);

            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Items = XmlRel.ReadItemArray<Dat151HashPair>(node, "Items");
            ItemCount = (Items?.Length ?? 0);
        }
        public override MetaHash[] GetGameHashes()
        {
            var list = new List<MetaHash>();
            if (Items != null)
            {
                foreach (var item in Items)
                {
                    list.Add(item.Hash1);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat151RadioStationList2 : Dat151RelData
    {
        public FlagsUint Flags { get; set; }
        public uint ItemCount { get; set; }
        public MetaHash[] ItemHashes { get; set; }

        public Dat151RadioStationList2(RelFile rel) : base(rel)
        {
            Type = Dat151RelType.RadioStationList2;
            TypeID = (byte)Type;
        }
        public Dat151RadioStationList2(RelData d, BinaryReader br) : base(d, br)
        {
            Flags = br.ReadUInt32();
            ItemCount = br.ReadUInt32();
            ItemHashes = new MetaHash[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                ItemHashes[i] = br.ReadUInt32();
            }

            long bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { } //no hits here


        }
        public override void Write(BinaryWriter bw)
        {
            //base.Write(bw);
            WriteTypeAndOffset(bw);

            bw.Write(Flags);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                bw.Write(ItemHashes[i]);
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.WriteHashItemArray(sb, ItemHashes, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            ItemHashes = XmlRel.ReadHashItemArray(node, "Items");
            ItemCount = (uint)(ItemHashes?.Length ?? 0);
        }
        public override MetaHash[] GetGameHashes()
        {
            return ItemHashes;
        }
    }




    #endregion




    #region dat4 (config)


    public enum Dat4ConfigType : byte
    {
        Int = 0,
        Int2 = 1,
        Float = 2,
        String = 3,
        Orientation = 5,
        VariableList = 7,
        WaveSlot = 8,
        WaveSlotsList = 9,
        UnkER = 10,
    }

    [TC(typeof(EXP))] public class Dat4ConfigData : RelData
    {
        public Dat4ConfigType Type { get; set; }
        public uint NameTableOffset { get; set; }
        public FlagsUint Flags { get; set; } = 0xAAAAAAAA;

        public Dat4ConfigData(RelFile rel) : base(rel) { }
        public Dat4ConfigData(RelFile rel, Dat4ConfigType type) : base(rel)
        {
            Type = type;
            TypeID = (byte)type;
        }
        public Dat4ConfigData(RelData d, BinaryReader br) : base(d)
        {
            Type = (Dat4ConfigType)TypeID;

            br.BaseStream.Position = 0; //1 byte was read already (TypeID)

            NameTableOffset = ((br.ReadUInt32() >> 8) & 0xFFFFFF);
            Flags = br.ReadUInt32();

            if (Flags != 0xAAAAAAAA)
            { }
        }

        public override void Write(BinaryWriter bw)
        {
            //don't use this as a fallback case, since it won't write as raw data
            //base.Write(bw);
            var val = ((NameTableOffset & 0xFFFFFF) << 8) + TypeID;
            bw.Write(val);
            bw.Write(Flags);
        }

        public override void WriteXml(StringBuilder sb, int indent)
        {
            //base.WriteXml(sb, indent);
            //RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
        }
        public override void ReadXml(XmlNode node)
        {
            //base.ReadXml(node);
            //Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Flags = 0xAAAAAAAA; //it's always this value so what's the point of putting it in XML?
        }

        public override string ToString()
        {
            return GetBaseString() + ": " + Type.ToString();
        }
    }

    [TC(typeof(EXP))] public class Dat4ConfigInt : Dat4ConfigData
    {
        public int Value { get; set; }

        public Dat4ConfigInt(RelFile rel) : base(rel)
        {
            Type = Dat4ConfigType.Int;
            TypeID = (byte)Type;
        }
        public Dat4ConfigInt(RelData d, BinaryReader br) : base(d, br)
        {
            Value = br.ReadInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(Value);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "Value", Value.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Value = Xml.GetChildIntAttribute(node, "Value", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat4ConfigInt2 : Dat4ConfigData
    {
        public int Value { get; set; }

        public Dat4ConfigInt2(RelFile rel) : base(rel)
        {
            Type = Dat4ConfigType.Int2;
            TypeID = (byte)Type;
        }
        public Dat4ConfigInt2(RelData d, BinaryReader br) : base(d, br)
        {
            Value = br.ReadInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(Value);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "Value", Value.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Value = Xml.GetChildIntAttribute(node, "Value", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat4ConfigFloat : Dat4ConfigData
    {
        public float Value { get; set; }

        public Dat4ConfigFloat(RelFile rel) : base(rel)
        {
            Type = Dat4ConfigType.Float;
            TypeID = (byte)Type;
        }
        public Dat4ConfigFloat(RelData d, BinaryReader br) : base(d, br)
        {
            Value = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(Value);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "Value", FloatUtil.ToString(Value));
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Value = Xml.GetChildFloatAttribute(node, "Value", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat4ConfigString : Dat4ConfigData
    {
        public string Value { get; set; }

        public Dat4ConfigString(RelFile rel) : base(rel)
        {
            Type = Dat4ConfigType.String;
            TypeID = (byte)Type;
        }
        public Dat4ConfigString(RelData d, BinaryReader br) : base(d, br)
        {
            var data = br.ReadBytes(64);
            Value = Encoding.ASCII.GetString(data).Replace("\0", "");

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);

            byte[] data = new byte[64];
            int len = Math.Min(Value?.Length ?? 0, 64);
            if (len > 0)
            {
                Encoding.ASCII.GetBytes(Value, 0, len, data, 0);
            }
            bw.Write(data);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.StringTag(sb, indent, "Value", Value);
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Value = Xml.GetChildInnerText(node, "Value");
        }
    }
    [TC(typeof(EXP))] public class Dat4ConfigOrientation : Dat4ConfigData
    {
        public Vector3 Vec1 { get; set; }
        public Vector3 Vec2 { get; set; }

        public Dat4ConfigOrientation(RelFile rel) : base(rel)
        {
            Type = Dat4ConfigType.Orientation;
            TypeID = (byte)Type;
        }
        public Dat4ConfigOrientation(RelData d, BinaryReader br) : base(d, br)
        {
            Vec1 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            Vec2 = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(Vec1.X);
            bw.Write(Vec1.Y);
            bw.Write(Vec1.Z);
            bw.Write(Vec2.X);
            bw.Write(Vec2.Y);
            bw.Write(Vec2.Z);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.SelfClosingTag(sb, indent, "Vec1 " + FloatUtil.GetVector3XmlString(Vec1));
            RelXml.SelfClosingTag(sb, indent, "Vec2 " + FloatUtil.GetVector3XmlString(Vec2));
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Vec1 = Xml.GetChildVector3Attributes(node, "Vec1");
            Vec2 = Xml.GetChildVector3Attributes(node, "Vec2");
        }
    }
    [TC(typeof(EXP))] public class Dat4ConfigVariableList : Dat4ConfigData
    {
        public int VariableCount { get; set; }
        public VariableValue[] Variables { get; set; }
        public class VariableValue : IMetaXmlItem
        {
            public MetaHash Name { get; set; }
            public float Value { get; set; }

            public VariableValue() { }
            public VariableValue(BinaryReader br)
            {
                Name = br.ReadUInt32();
                Value = br.ReadSingle();
            }
            public void Write(BinaryWriter bw)
            {
                bw.Write(Name);
                bw.Write(Value);
            }
            public void WriteXml(StringBuilder sb, int indent)
            {
                RelXml.StringTag(sb, indent, "Name", RelXml.HashString(Name));
                RelXml.ValueTag(sb, indent, "Value", FloatUtil.ToString(Value));
            }
            public void ReadXml(XmlNode node)
            {
                Name = XmlRel.GetHash(Xml.GetChildInnerText(node, "Name"));
                Value = Xml.GetChildFloatAttribute(node, "Value", "value");
            }
            public override string ToString()
            {
                return Name + ": " + Value.ToString();
            }
        }

        public Dat4ConfigVariableList(RelFile rel) : base(rel)
        {
            Type = Dat4ConfigType.VariableList;
            TypeID = (byte)Type;
        }
        public Dat4ConfigVariableList(RelData d, BinaryReader br) : base(d, br)
        {
            VariableCount = br.ReadInt32();
            Variables = new VariableValue[VariableCount];
            for (int i = 0; i < VariableCount; i++)
            {
                Variables[i] = new VariableValue(br);
            }
            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(VariableCount);
            for (int i = 0; i < VariableCount; i++)
            {
                Variables[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.WriteItemArray(sb, Variables, indent, "Variables");
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Variables = XmlRel.ReadItemArray<VariableValue>(node, "Variables");
            VariableCount = (Variables?.Length ?? 0);
        }
    }
    [TC(typeof(EXP))] public class Dat4ConfigWaveSlot : Dat4ConfigData
    {
        public int Unk1 { get; set; }
        public int MaxHeaderSize { get; set; }
        public int Size { get; set; }
        public MetaHash StaticBank { get; set; }
        public int MaxDataSize { get; set; }
        public int Unk6 { get; set; }

        public Dat4ConfigWaveSlot(RelFile rel) : base(rel)
        {
            Type = Dat4ConfigType.WaveSlot;
            TypeID = (byte)Type;
        }
        public Dat4ConfigWaveSlot(RelData d, BinaryReader br) : base(d, br)
        {
            Unk1 = br.ReadInt32();
            MaxHeaderSize = br.ReadInt32();
            Size = br.ReadInt32();
            StaticBank = br.ReadUInt32();
            MaxDataSize = br.ReadInt32();
            Unk6 = br.ReadInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(Unk1);
            bw.Write(MaxHeaderSize);
            bw.Write(Size);
            bw.Write(StaticBank);
            bw.Write(MaxDataSize);
            bw.Write(Unk6);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "Unk1", Unk1.ToString());
            RelXml.ValueTag(sb, indent, "MaxHeaderSize", MaxHeaderSize.ToString());
            RelXml.ValueTag(sb, indent, "Size", Size.ToString());
            RelXml.StringTag(sb, indent, "StaticBank", RelXml.HashString(StaticBank));
            RelXml.ValueTag(sb, indent, "MaxDataSize", MaxDataSize.ToString());
            RelXml.ValueTag(sb, indent, "Unk6", Unk6.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Unk1 = Xml.GetChildIntAttribute(node, "Unk1", "value");
            MaxHeaderSize = Xml.GetChildIntAttribute(node, "MaxHeaderSize", "value");
            Size = Xml.GetChildIntAttribute(node, "Size", "value");
            StaticBank = XmlRel.GetHash(Xml.GetChildInnerText(node, "StaticBank"));
            MaxDataSize = Xml.GetChildIntAttribute(node, "MaxDataSize", "value");
            Unk6 = Xml.GetChildIntAttribute(node, "Unk6", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat4ConfigWaveSlotsList : Dat4ConfigData
    {
        public int WaveSlotsCount { get; set; }
        public MetaHash[] WaveSlots { get; set; }

        public Dat4ConfigWaveSlotsList(RelFile rel) : base(rel)
        {
            Type = Dat4ConfigType.WaveSlotsList;
            TypeID = (byte)Type;
        }
        public Dat4ConfigWaveSlotsList(RelData d, BinaryReader br) : base(d, br)
        {
            WaveSlotsCount = br.ReadInt32();
            WaveSlots = new MetaHash[WaveSlotsCount];
            for (int i = 0; i < WaveSlotsCount; i++)
            {
                WaveSlots[i] = br.ReadUInt32();
            }
            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(WaveSlotsCount);
            for (int i = 0; i < WaveSlotsCount; i++)
            {
                bw.Write(WaveSlots[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.WriteHashItemArray(sb, WaveSlots, indent, "WaveSlots");
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            WaveSlots = XmlRel.ReadHashItemArray(node, "WaveSlots");
            WaveSlotsCount = (WaveSlots?.Length ?? 0);
        }
        public override uint[] GetHashTableOffsets()
        {
            var offsets = new List<uint>();
            for (uint i = 0; i < WaveSlotsCount; i++)
            {
                offsets.Add(8 + i * 4);
            }
            return offsets.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat4ConfigUnkER : Dat4ConfigData
    {
        float Unk1 { get; set; }
        float Unk2 { get; set; }
        float Unk3 { get; set; }
        float Unk4 { get; set; }
        float Unk5 { get; set; }
        float Unk6 { get; set; }
        float Unk7 { get; set; }
        int UnkItemsCount { get; set; }
        UnkItem[] UnkItems { get; set; }
        Vector4 UnkVec1 { get; set; }
        Vector4 UnkVec2 { get; set; }
        Vector4 UnkVec3 { get; set; }
        Vector4 UnkVec4 { get; set; }
        Vector4 UnkVec5 { get; set; }
        Vector4 UnkVec6 { get; set; }
        Vector4 UnkVec7 { get; set; }
        Vector4 UnkVec8 { get; set; }
        Vector4 UnkVec9 { get; set; }
        int UnkVecCount1 { get; set; }
        Vector4[] UnkVecs1 { get; set; }
        int UnkVecCount2 { get; set; }
        Vector4[] UnkVecs2 { get; set; }
        int UnkVecCount3 { get; set; }
        Vector4[] UnkVecs3 { get; set; }


        public class UnkItem : IMetaXmlItem
        {
            public float UnkFloat { get; set; }
            public int UnkInt { get; set; }

            public UnkItem() { }
            public UnkItem(BinaryReader br)
            {
                UnkFloat = br.ReadSingle();
                UnkInt = br.ReadInt32();
            }
            public void Write(BinaryWriter bw)
            {
                bw.Write(UnkFloat);
                bw.Write(UnkInt);
            }
            public void WriteXml(StringBuilder sb, int indent)
            {
                RelXml.ValueTag(sb, indent, "UnkFloat", FloatUtil.ToString(UnkFloat));
                RelXml.ValueTag(sb, indent, "UnkInt", UnkInt.ToString());
            }
            public void ReadXml(XmlNode node)
            {
                UnkFloat = Xml.GetChildFloatAttribute(node, "UnkFloat", "value");
                UnkInt = Xml.GetChildIntAttribute(node, "UnkInt", "value");
            }
            public override string ToString()
            {
                return FloatUtil.ToString(UnkFloat) + ", " + UnkInt.ToString();
            }
        }


        public Dat4ConfigUnkER(RelFile rel) : base(rel)
        {
            Type = Dat4ConfigType.UnkER;
            TypeID = (byte)Type;
        }
        public Dat4ConfigUnkER(RelData d, BinaryReader br) : base(d, br)
        {
            Unk1 = br.ReadSingle();
            Unk2 = br.ReadSingle();
            Unk3 = br.ReadSingle();
            Unk4 = br.ReadSingle();
            Unk5 = br.ReadSingle();
            Unk6 = br.ReadSingle();
            Unk7 = br.ReadSingle();
            UnkItemsCount = br.ReadInt32();
            UnkItems = new UnkItem[UnkItemsCount];
            for (int i = 0; i < UnkItemsCount; i++)
            {
                UnkItems[i] = new UnkItem(br);
            }
            UnkVec1 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            UnkVec2 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            UnkVec3 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            UnkVec4 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            UnkVec5 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            UnkVec6 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            UnkVec7 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            UnkVec8 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            UnkVec9 = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            UnkVecCount1 = br.ReadInt32();
            UnkVecs1 = new Vector4[UnkVecCount1];
            for (int i = 0; i < UnkVecCount1; i++)
            {
                UnkVecs1[i] = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            }
            UnkVecCount2 = br.ReadInt32();
            UnkVecs2 = new Vector4[UnkVecCount1];
            for (int i = 0; i < UnkVecCount2; i++)
            {
                UnkVecs2[i] = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            }
            UnkVecCount3 = br.ReadInt32();
            UnkVecs3 = new Vector4[UnkVecCount1];
            for (int i = 0; i < UnkVecCount3; i++)
            {
                UnkVecs3[i] = new Vector4(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            base.Write(bw);
            bw.Write(Unk1);
            bw.Write(Unk2);
            bw.Write(Unk3);
            bw.Write(Unk4);
            bw.Write(Unk5);
            bw.Write(Unk6);
            bw.Write(Unk7);
            bw.Write(UnkItemsCount);
            for (int i = 0; i < UnkItemsCount; i++)
            {
                UnkItems[i].Write(bw);
            }
            bw.Write(UnkVec1.X);
            bw.Write(UnkVec1.Y);
            bw.Write(UnkVec1.Z);
            bw.Write(UnkVec1.W);
            bw.Write(UnkVec2.X);
            bw.Write(UnkVec2.Y);
            bw.Write(UnkVec2.Z);
            bw.Write(UnkVec2.W);
            bw.Write(UnkVec3.X);
            bw.Write(UnkVec3.Y);
            bw.Write(UnkVec3.Z);
            bw.Write(UnkVec3.W);
            bw.Write(UnkVec4.X);
            bw.Write(UnkVec4.Y);
            bw.Write(UnkVec4.Z);
            bw.Write(UnkVec4.W);
            bw.Write(UnkVec5.X);
            bw.Write(UnkVec5.Y);
            bw.Write(UnkVec5.Z);
            bw.Write(UnkVec5.W);
            bw.Write(UnkVec6.X);
            bw.Write(UnkVec6.Y);
            bw.Write(UnkVec6.Z);
            bw.Write(UnkVec6.W);
            bw.Write(UnkVec7.X);
            bw.Write(UnkVec7.Y);
            bw.Write(UnkVec7.Z);
            bw.Write(UnkVec7.W);
            bw.Write(UnkVec8.X);
            bw.Write(UnkVec8.Y);
            bw.Write(UnkVec8.Z);
            bw.Write(UnkVec8.W);
            bw.Write(UnkVec9.X);
            bw.Write(UnkVec9.Y);
            bw.Write(UnkVec9.Z);
            bw.Write(UnkVec9.W);
            bw.Write(UnkVecCount1);
            for (int i = 0; i < UnkVecCount1; i++)
            {
                bw.Write(UnkVecs1[i].X);
                bw.Write(UnkVecs1[i].Y);
                bw.Write(UnkVecs1[i].Z);
                bw.Write(UnkVecs1[i].W);
            }
            bw.Write(UnkVecCount2);
            for (int i = 0; i < UnkVecCount2; i++)
            {
                bw.Write(UnkVecs2[i].X);
                bw.Write(UnkVecs2[i].Y);
                bw.Write(UnkVecs2[i].Z);
                bw.Write(UnkVecs2[i].W);
            }
            bw.Write(UnkVecCount3);
            for (int i = 0; i < UnkVecCount3; i++)
            {
                bw.Write(UnkVecs3[i].X);
                bw.Write(UnkVecs3[i].Y);
                bw.Write(UnkVecs3[i].Z);
                bw.Write(UnkVecs3[i].W);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            base.WriteXml(sb, indent);
            RelXml.ValueTag(sb, indent, "Unk1", FloatUtil.ToString(Unk1));
            RelXml.ValueTag(sb, indent, "Unk2", FloatUtil.ToString(Unk2));
            RelXml.ValueTag(sb, indent, "Unk3", FloatUtil.ToString(Unk3));
            RelXml.ValueTag(sb, indent, "Unk4", FloatUtil.ToString(Unk4));
            RelXml.ValueTag(sb, indent, "Unk5", FloatUtil.ToString(Unk5));
            RelXml.ValueTag(sb, indent, "Unk6", FloatUtil.ToString(Unk6));
            RelXml.ValueTag(sb, indent, "Unk7", FloatUtil.ToString(Unk7));
            RelXml.WriteItemArray(sb, UnkItems, indent, "UnkItems");
            RelXml.SelfClosingTag(sb, indent, "UnkVec1 " + FloatUtil.GetVector4XmlString(UnkVec1));
            RelXml.SelfClosingTag(sb, indent, "UnkVec2 " + FloatUtil.GetVector4XmlString(UnkVec2));
            RelXml.SelfClosingTag(sb, indent, "UnkVec3 " + FloatUtil.GetVector4XmlString(UnkVec3));
            RelXml.SelfClosingTag(sb, indent, "UnkVec4 " + FloatUtil.GetVector4XmlString(UnkVec4));
            RelXml.SelfClosingTag(sb, indent, "UnkVec5 " + FloatUtil.GetVector4XmlString(UnkVec5));
            RelXml.SelfClosingTag(sb, indent, "UnkVec6 " + FloatUtil.GetVector4XmlString(UnkVec6));
            RelXml.SelfClosingTag(sb, indent, "UnkVec7 " + FloatUtil.GetVector4XmlString(UnkVec7));
            RelXml.SelfClosingTag(sb, indent, "UnkVec8 " + FloatUtil.GetVector4XmlString(UnkVec8));
            RelXml.SelfClosingTag(sb, indent, "UnkVec9 " + FloatUtil.GetVector4XmlString(UnkVec9));
            RelXml.WriteRawArray(sb, UnkVecs1, indent, "UnkVecs1", "", RelXml.FormatVector4, 1);
            RelXml.WriteRawArray(sb, UnkVecs2, indent, "UnkVecs2", "", RelXml.FormatVector4, 1);
            RelXml.WriteRawArray(sb, UnkVecs3, indent, "UnkVecs3", "", RelXml.FormatVector4, 1);
        }
        public override void ReadXml(XmlNode node)
        {
            base.ReadXml(node);
            Unk1 = Xml.GetChildFloatAttribute(node, "Unk1", "value");
            Unk2 = Xml.GetChildFloatAttribute(node, "Unk2", "value");
            Unk3 = Xml.GetChildFloatAttribute(node, "Unk3", "value");
            Unk4 = Xml.GetChildFloatAttribute(node, "Unk4", "value");
            Unk5 = Xml.GetChildFloatAttribute(node, "Unk5", "value");
            Unk6 = Xml.GetChildFloatAttribute(node, "Unk6", "value");
            Unk7 = Xml.GetChildFloatAttribute(node, "Unk7", "value");
            UnkItems = XmlRel.ReadItemArray<UnkItem>(node, "UnkItems");
            UnkItemsCount = (UnkItems?.Length ?? 0);
            UnkVec1 = Xml.GetChildVector4Attributes(node, "UnkVec1");
            UnkVec2 = Xml.GetChildVector4Attributes(node, "UnkVec2");
            UnkVec3 = Xml.GetChildVector4Attributes(node, "UnkVec3");
            UnkVec4 = Xml.GetChildVector4Attributes(node, "UnkVec4");
            UnkVec5 = Xml.GetChildVector4Attributes(node, "UnkVec5");
            UnkVec6 = Xml.GetChildVector4Attributes(node, "UnkVec6");
            UnkVec7 = Xml.GetChildVector4Attributes(node, "UnkVec7");
            UnkVec8 = Xml.GetChildVector4Attributes(node, "UnkVec8");
            UnkVec9 = Xml.GetChildVector4Attributes(node, "UnkVec9");
            UnkVecs1 = Xml.GetChildRawVector4Array(node, "UnkVecs1");
            UnkVecs2 = Xml.GetChildRawVector4Array(node, "UnkVecs2");
            UnkVecs3 = Xml.GetChildRawVector4Array(node, "UnkVecs3");
            UnkVecCount1 = UnkVecs1?.Length ?? 0;
            UnkVecCount2 = UnkVecs2?.Length ?? 0;
            UnkVecCount3 = UnkVecs3?.Length ?? 0;
        }
    }


    //[TC(typeof(EXP))] public class Dat4ConfigBlankTemplateItem : Dat4ConfigData
    //{
    //    public Dat4ConfigBlankTemplateItem(RelFile rel) : base(rel)
    //    {
    //        Type = Dat4ConfigType.RELTYPE;
    //        TypeID = (byte)Type;
    //    }
    //    public Dat4ConfigBlankTemplateItem(RelData d, BinaryReader br) : base(d, br)
    //    {
    //        var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
    //        if (bytesleft != 0)
    //        { }
    //    }
    //    public override void Write(BinaryWriter bw)
    //    {
    //        base.Write(bw);
    //    }
    //    public override void WriteXml(StringBuilder sb, int indent)
    //    {
    //        base.WriteXml(sb, indent);
    //    }
    //    public override void ReadXml(XmlNode node)
    //    {
    //        base.ReadXml(node);
    //    }
    //}




    #endregion
    
    
    
    
    #region dat4 (speech)

    public enum Dat4SpeechType : byte
    {
        ByteArray = 0,
        Hash = 4,
        Container = 8,
    }

    [TC(typeof(EXP))] public class Dat4SpeechData : RelData
    {
        public Dat4SpeechType Type { get; set; }

        public uint NameTableOffset { get; set; }
        public MetaHash ContainerHash { get; set; }
        public MetaHash Hash { get; set; }


        public Dat4SpeechData(RelFile rel) : base(rel)
        { }
        public Dat4SpeechData(RelData d, BinaryReader br) : base(d)
        {
            br.BaseStream.Position = 0; //1 byte was read already (TypeID)


            if ((TypeID == 4) && (br.BaseStream.Length == 8))
            {
                NameTableOffset = ((br.ReadUInt32() >> 8) & 0xFFFFFF);
                ContainerHash = br.ReadUInt32();
            }
        }

        public override void Write(BinaryWriter bw)
        {
            switch (Type)
            {
                case Dat4SpeechType.Hash:
                    bw.Write(Hash);
                    break;
                case Dat4SpeechType.Container:
                    bw.Write(((NameTableOffset & 0xFFFFFF) << 8) + 4 /*TypeID*/);
                    bw.Write(ContainerHash);
                    break;
                default:
                    bw.Write(Data);
                    break;
            }
        }

        public override void WriteXml(StringBuilder sb, int indent)
        {
            switch (Type)
            {
                case Dat4SpeechType.Hash:
                    RelXml.StringTag(sb, indent, "Hash", RelXml.HashString(Hash));
                    break;
                case Dat4SpeechType.Container:
                    RelXml.StringTag(sb, indent, "ContainerHash", RelXml.HashString(ContainerHash));
                    break;
                default:
                    RelXml.WriteRawArray(sb, Data, indent, "RawData", "", RelXml.FormatHexByte, 16);
                    break;
            }
        }
        public override void ReadXml(XmlNode node)
        {
            switch (Type)
            {
                case Dat4SpeechType.Hash:
                    Hash = XmlRel.GetHash(Xml.GetChildInnerText(node, "Hash"));
                    break;
                case Dat4SpeechType.Container:
                    ContainerHash = XmlRel.GetHash(Xml.GetChildInnerText(node, "ContainerHash"));
                    break;
                default:
                    var rawnode = node.SelectSingleNode("RawData");
                    if (rawnode != null)
                    {
                        Data = Xml.GetRawByteArray(rawnode);
                        DataLength = (uint)Data.Length;
                    }
                    break;
            }
        }

        public override uint[] GetHashTableOffsets()
        {
            switch (Type)
            {
                case Dat4SpeechType.Hash:
                    return new uint[] { 0 };
            }
            return null;
        }
        public override uint[] GetPackTableOffsets()
        {
            switch (Type)
            {
                case Dat4SpeechType.Container:
                    return new uint[] { 4 };
            }
            return null;
        }

        public override string ToString()
        {
            switch (Type)
            {
                case Dat4SpeechType.Hash:
                    return GetBaseString() + ": " + Type.ToString() + ": " + Hash.ToString();
                case Dat4SpeechType.Container:
                    return GetBaseString() + ": " + Type.ToString() + ": " + ContainerHash.ToString();
            }
            return GetBaseString();
        }

    }


    #endregion




    #region dat10


    public enum Dat10RelType : byte
    {
        SynthPreset = 1,
        Synth = 3,
    }

    [TC(typeof(EXP))] public class Dat10RelData : RelData
    {
        public Dat10RelType Type { get; set; }
        public uint NameTableOffset { get; set; }
        public FlagsUint Flags { get; set; }

        public Dat10RelData(RelFile rel) : base(rel) { }
        public Dat10RelData(RelFile rel, Dat10RelType type) : base(rel)
        {
            Type = type;
            TypeID = (byte)type;
        }
        public Dat10RelData(RelData d, BinaryReader br) : base(d)
        {
            Type = (Dat10RelType)TypeID;

            br.BaseStream.Position = 0; //1 byte was read already (TypeID)

            NameTableOffset = ((br.ReadUInt32() >> 8) & 0xFFFFFF);
            Flags = br.ReadUInt32();
        }

        public void WriteTypeAndOffsetAndFlags(BinaryWriter bw)
        {
            var val = ((NameTableOffset & 0xFFFFFF) << 8) + TypeID;
            bw.Write(val);
            bw.Write(Flags);
        }

        public override string ToString()
        {
            return GetBaseString() + ": " + Type.ToString();
        }
    }

    [TC(typeof(EXP))] public class Dat10SynthPresetVariable : IMetaXmlItem
    {
        public MetaHash Name { get; set; }
        public float Value1 { get; set; }
        public float Value2 { get; set; }

        public Dat10SynthPresetVariable()
        { }
        public Dat10SynthPresetVariable(BinaryReader br)
        {
            Name = br.ReadUInt32();
            Value1 = br.ReadSingle();
            Value2 = br.ReadSingle();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Name);
            bw.Write(Value1);
            bw.Write(Value2);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Name", RelXml.HashString(Name));
            RelXml.ValueTag(sb, indent, "Value1", FloatUtil.ToString(Value1));
            RelXml.ValueTag(sb, indent, "Value2", FloatUtil.ToString(Value2));
        }
        public void ReadXml(XmlNode node)
        {
            Name = XmlRel.GetHash(Xml.GetChildInnerText(node, "Name"));
            Value1 = Xml.GetChildFloatAttribute(node, "Value1", "value");
            Value2 = Xml.GetChildFloatAttribute(node, "Value2", "value");
        }
        public override string ToString()
        {
            return Name.ToString() + ": " + Value1.ToString() + ", " + Value2.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat10SynthPreset : Dat10RelData
    {
        public byte VariableCount { get; set; }
        public Dat10SynthPresetVariable[] Variables { get; set; }

        public Dat10SynthPreset(RelFile rel) : base(rel)
        {
            Type = Dat10RelType.SynthPreset;
            TypeID = (byte)Type;
        }
        public Dat10SynthPreset(RelData d, BinaryReader br) : base(d, br)
        {
            VariableCount = br.ReadByte();
            Variables = new Dat10SynthPresetVariable[VariableCount];
            for (int i = 0; i < VariableCount; i++)
            {
                Variables[i] = new Dat10SynthPresetVariable(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(VariableCount);
            for (int i = 0; i < VariableCount; i++)
            {
                Variables[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.WriteItemArray(sb, Variables, indent, "Variables");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Variables = XmlRel.ReadItemArray<Dat10SynthPresetVariable>(node, "Variables");
            VariableCount = (byte)(Variables?.Length ?? 0);
        }
    }
    [TC(typeof(EXP))] public class Dat10SynthVariable : IMetaXmlItem
    {
        public MetaHash Name { get; set; }
        public float Value { get; set; }

        public Dat10SynthVariable()
        { }
        public Dat10SynthVariable(BinaryReader br)
        {
            Name = br.ReadUInt32();
            Value = br.ReadSingle();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Name);
            bw.Write(Value);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Name", RelXml.HashString(Name));
            RelXml.ValueTag(sb, indent, "Value", FloatUtil.ToString(Value));
        }
        public void ReadXml(XmlNode node)
        {
            Name = XmlRel.GetHash(Xml.GetChildInnerText(node, "Name"));
            Value = Xml.GetChildFloatAttribute(node, "Value", "value");
        }
        public override string ToString()
        {
            return Name.ToString() + ": " + Value.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat10Synth : Dat10RelData
    {
        // limits hardcoded in the .exe
        public const int MaxStateBlocks = 64;
        public const int MaxRegisters = 48;
        public const int MaxBuffers = 16;
        public const int MaxOutputs = 4;

        public int BuffersCount { get; set; }//buffers count           (4)  (for synth_ambient_aircon_full)
        public int RegistersCount { get; set; }//registers count       (21)
        public int OutputsCount { get; set; }//outputs count           (1)
        public byte[] OutputsIndices { get; set; }//outputs indices: determines the buffers used as outputs   (1, 0, 0, 0)
        public int BytecodeLength { get; set; }//bytecode length       (504)
        public int StateBlocksCount { get; set; }//state blocks count  (18)
        public int RuntimeCost { get; set; }//runtime cost             (50)
        public byte[] Bytecode { get; set; }
        public int ConstantsCount { get; set; }//constants count       (21)
        public float[] Constants { get; set; }//constants (floats)
        public int VariablesCount { get; set; }//variables count       (8)
        public Dat10SynthVariable[] Variables { get; set; }//variables

        public Dat10Synth(RelFile rel) : base(rel)
        {
            Type = Dat10RelType.Synth;
            TypeID = (byte)Type;
        }
        public Dat10Synth(RelData d, BinaryReader br) : base(d, br)
        {
            BuffersCount = br.ReadInt32();//buffers count           (4)  (for synth_ambient_aircon_full)
            RegistersCount = br.ReadInt32();//registers count       (21)
            OutputsCount = br.ReadInt32();//outputs count           (1)
            OutputsIndices = br.ReadBytes(MaxOutputs);//outputs indices      (1, 0, 0, 0)
            BytecodeLength = br.ReadInt32();//bytecode length       (504)
            StateBlocksCount = br.ReadInt32();//state blocks count  (18)
            RuntimeCost = br.ReadInt32();//runtime cost             (50)
            Bytecode = br.ReadBytes(BytecodeLength);
            ConstantsCount = br.ReadInt32(); //constants count      (21)              
            Constants = new float[ConstantsCount];//constants (floats)
            for (int i = 0; i < ConstantsCount; i++)
            {
                Constants[i] = br.ReadSingle();
            }
            VariablesCount = br.ReadInt32(); //variables count      (8)
            Variables = new Dat10SynthVariable[VariablesCount];//variables
            for (int i = 0; i < VariablesCount; i++)
            {
                Variables[i] = new Dat10SynthVariable(br);
            }

            if (d.NameHash == 2095626595)//synth_ambient_aircon_full
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(BuffersCount);
            bw.Write(RegistersCount);
            bw.Write(OutputsCount);
            bw.Write(OutputsIndices);
            bw.Write(BytecodeLength);
            bw.Write(StateBlocksCount);
            bw.Write(RuntimeCost);
            bw.Write(Bytecode);
            bw.Write(ConstantsCount);
            for (int i = 0; i < ConstantsCount; i++)
            {
                bw.Write(Constants[i]);
            }
            bw.Write(VariablesCount);
            for (int i = 0; i < VariablesCount; i++)
            {
                Variables[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.WriteItemArray(sb, Variables, indent, "Variables");

            var disasm = Disassemble(Bytecode, Constants, Variables, false);
            var reasm = Assemble(disasm.Disassembly, Variables);//TODO: adjust disassembly code to make this not necessary
            RelXml.OpenTag(sb, indent, "Assembly");
            var reader = new StringReader(disasm.Disassembly);
            string line;
            while ((line = reader.ReadLine()) != null)
            {
                RelXml.Indent(sb, indent + 1);
                sb.AppendLine(line);
            }
            RelXml.CloseTag(sb, indent, "Assembly");

            var outputs = new List<byte>();
            for (int i = 0; i < OutputsCount; i++)
            {
                if (i >= OutputsIndices.Length) break;
                outputs.Add(OutputsIndices[i]);
            }
            RelXml.WriteRawArray(sb, outputs.ToArray(), indent, "OutputBuffers", "", arrRowSize: 4);

            var extraConstants = new List<float>();
            for (int i = reasm.Constants.Count; i < ConstantsCount; i++)
            {
                extraConstants.Add(Constants[i]);
            }
            if (extraConstants.Count > 0)
            {
                RelXml.WriteRawArray(sb, extraConstants.ToArray(), indent, "ExtraConstants", "", FloatUtil.ToString, 1);
            }

            var extraRegisters = RegistersCount - reasm.RegistersCount;
            if (extraRegisters > 0)
            {
                RelXml.ValueTag(sb, indent, "ExtraRegisters", extraRegisters.ToString());
            }

            RelXml.ValueTag(sb, indent, "RuntimeCost", RuntimeCost.ToString());//TODO: calculate this during reassembly

        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Variables = XmlRel.ReadItemArray<Dat10SynthVariable>(node, "Variables");
            VariablesCount = (Variables?.Length ?? 0);

            var assembly = Xml.GetChildInnerText(node, "Assembly");
            var assembled = Assemble(assembly, Variables);
            Bytecode = assembled.Bytecode;
            BytecodeLength = (Bytecode?.Length ?? 0);
            BuffersCount = assembled.BuffersCount;
            StateBlocksCount = assembled.StateBlocksCount;

            var outputs = Xml.GetChildRawByteArray(node, "OutputBuffers", fromBase: 10).ToList();
            OutputsCount = outputs.Count;
            for (int i = OutputsCount; i < 4; i++)
            {
                outputs.Add(0);
            }
            OutputsIndices = outputs.ToArray();


            var extraConstants = Xml.GetChildRawFloatArray(node, "ExtraConstants");
            foreach (var extraConstant in extraConstants)
            {
                assembled.Constants.Add(extraConstant);
            }
            Constants = assembled.Constants.ToArray();
            ConstantsCount = (Constants?.Length ?? 0);

            var extraRegisters = Xml.GetChildIntAttribute(node, "ExtraRegisters", "value");
            RegistersCount = assembled.RegistersCount + extraRegisters;

            RuntimeCost = Xml.GetChildIntAttribute(node, "RuntimeCost", "value");

        }


        public void TestDisassembly()
        {
            var errors = new List<string>();
            var disasm = Disassemble(this.Bytecode, this.Constants, this.Variables, true);
            var reasm = Assemble(disasm.Disassembly, this.Variables, (s,i) => errors.Add(s));
            var disasm2 = Disassemble(reasm.Bytecode, reasm.Constants.ToArray(), this.Variables, true);

            if (errors.Count > 0)
            { }//no hit
            if (disasm.Disassembly != disasm2.Disassembly)
            { } //no hit!
            if (reasm.Bytecode.Length != Bytecode.Length)
            { }//no hit
            else
            {
                for (int i = 0; i < reasm.Bytecode.Length; i++)
                {
                    if (reasm.Bytecode[i] != Bytecode[i])
                    { break; }//no hit!
                }
            }
            if (reasm.BuffersCount != this.BuffersCount)
            { }//no hit
            if (reasm.StateBlocksCount != this.StateBlocksCount)
            { }//no hit
            if (reasm.Constants.Count <= Constants.Length)
            {
                for (int i = 0; i < reasm.Constants.Count; i++)
                {
                    if (reasm.Constants[i] != Constants[i])
                    { break; }//no hit
                }
            }
            if (reasm.Constants.Count != Constants.Length)
            {
                if (reasm.Constants.Count != Constants.Length - 1)
                { }//no hit
                else
                {
                    var lastc = Constants[Constants.Length - 1];
                    switch (lastc) //what is this?
                    {
                        case 0.0015f:
                        case 0.3595f:
                        case 0.323215f:
                        case 0.4435f:
                        case 0.5095f:
                        case 12000f:
                        case 3.590499f:
                        case 0.829645f:
                        case 0.5745f:
                        case -1f:
                        case 0.01f:
                        case 0.561f:
                        case 1.0754323f:
                        case 0.1845f:
                        case 0.508f:
                        case 0.006f:
                            break;
                        default:
                            break;//no hit
                    }
                }
            }
            if (reasm.VariablesCount != this.VariablesCount)
            { }//lots of hits.......
            if (reasm.RegistersCount != this.RegistersCount)
            {//quite a few hits
                var extregs = this.RegistersCount - reasm.RegistersCount;
                switch (extregs)
                {
                    case 1:
                    case 2:
                    case 3:
                    case 4:
                        break;
                    default:
                        break;//no hits
                }
            }

        }


        public class DisassembleResult
        {
            public string Disassembly { get; set; }
            public List<Instruction> Instructions { get; set; } = new List<Instruction>();
        }

        public static DisassembleResult Disassemble(byte[] bytecode, float[] constants, Dat10SynthVariable[] variables, bool includeBytecode)
        {
            // TODO(alexguirre): THE NEW bytecodeReader DOESN'T LOOK QUITE RIGHT YET
            var bytecodeReader = new BinaryReader(new MemoryStream(bytecode));
            var sb = new StringBuilder();
            var dr = new DisassembleResult();
            for (int i = 0; i < bytecode.Length;)
            {
                var opcode = bytecode[i + 1];

                if (Enum.IsDefined(typeof(Opcode), (Opcode)opcode))
                {
                    var inst = Decode(bytecodeReader);
                    var size = inst.Size;

                    sb.Append(inst.ToString(constants, variables));
                    if (includeBytecode)
                    {
                        sb.Append("    ; ");
                        for (int k = 0; k < size; k++)
                        {
                            sb.Append(bytecode[i + k].ToString("X2"));
                            sb.Append(' ');
                        }
                    }
                    sb.AppendLine();
                    i += size;

                    dr.Instructions.Add(inst);
                }
                else
                {
                    sb.AppendLine($"Unknown opcode {opcode:X2}");
                    sb.Append("\t\t");
                    for (int k = 0; k < 16 && (i + k) < bytecode.Length; k++)
                    {
                        sb.Append(bytecode[i + k].ToString("X2"));
                        sb.Append(' ');
                    }
                    break;
                }

                if ((Opcode)opcode == Opcode.FINISH)
                {
                    break;
                }
            }

            dr.Disassembly = sb.ToString();

            return dr;
        }

        public static Instruction[] DisassembleGetInstructions(byte[] bytecode, float[] constants, Dat10SynthVariable[] variables)
        {
            // TODO(alexguirre): THE NEW bytecodeReader DOESN'T LOOK QUITE RIGHT YET
            var bytecodeReader = new BinaryReader(new MemoryStream(bytecode));
            var instructions = new List<Instruction>(128);
            for (int i = 0; i < bytecode.Length;)
            {
                var opcode = bytecode[i + 1];

                if (Enum.IsDefined(typeof(Opcode), (Opcode)opcode))
                {
                    var inst = Decode(bytecodeReader);
                    instructions.Add(inst);
                    i += inst.Size;
                }
                else
                {
                    throw new Exception($"Unknown opcode {opcode:X2}");
                }

                if ((Opcode)opcode == Opcode.FINISH)
                {
                    break;
                }
            }

            return instructions.ToArray();
        }

        public static int SizeOf(Opcode opcode, int inputs, int outputs)
        {
            switch (opcode)
            {
                case Opcode.COPY_BUFFER: return 4 + (2 * outputs);
                case Opcode.COPY_REGISTER: return 4 + (2 * outputs);
                case Opcode.CONVERT_BUFFER_TO_DENORMALIZED: return 4;
                case Opcode.CONVERT_SCALAR_TO_DENORMALIZED: return 6;
                case Opcode.CONVERT_BUFFER_TO_NORMALIZED: return 4;
                case Opcode.CONVERT_SCALAR_TO_NORMALIZED: return 6;
                case Opcode.FIRST_OF_BUFFER: return 6;
                case Opcode.MULTIPLY_BUFFER_BUFFER: return 6;
                case Opcode.MULTIPLY_BUFFER_SCALAR: return 6;
                case Opcode.MULTIPLY_SCALAR_SCALAR: return 8;
                case Opcode.SUM_BUFFER_BUFFER: return 6;
                case Opcode.SUM_BUFFER_SCALAR: return 6;
                case Opcode.SUM_SCALAR_SCALAR: return 8;
                case Opcode.SUBTRACT_BUFFER_BUFFER: return 6;
                case Opcode.SUBTRACT_BUFFER_SCALAR: return 6;
                case Opcode.SUBTRACT_SCALAR_BUFFER: return 8;
                case Opcode.SUBTRACT_SCALAR_SCALAR: return 8;
                case Opcode.DIVIDE_BUFFER_BUFFER: return 6;
                case Opcode.DIVIDE_BUFFER_SCALAR: return 6;
                case Opcode.DIVIDE_SCALAR_SCALAR: return 8;
                case Opcode.RESCALE_BUFFER_BUFFER: return 12;
                case Opcode.RESCALE_BUFFER_SCALAR: return 12;
                case Opcode.RESCALE_SCALAR_SCALAR: return 14;
                case Opcode.HARD_KNEE_BUFFER: return 6;
                case Opcode.HARD_KNEE_SCALAR_SCALAR: return 8;
                case Opcode.NOISE: return 4;
                case Opcode.RANDOM: return 12;
                case Opcode.ABS_BUFFER: return 4;
                case Opcode.ABS_SCALAR: return 6;
                case Opcode.FLOOR_BUFFER: return 4;
                case Opcode.FLOOR_SCALAR: return 6;
                case Opcode.CEIL_BUFFER: return 4;
                case Opcode.CEIL_SCALAR: return 6;
                case Opcode.ROUND_BUFFER: return 4;
                case Opcode.ROUND_SCALAR: return 6;
                case Opcode.SIGN_BUFFER: return 4;
                case Opcode.SIGN_SCALAR: return 6;
                case Opcode.MODULO_BUFFER: return 6;
                case Opcode.MODULO_SCALAR: return 8;
                case Opcode.POW_SCALAR: return 8;
                case Opcode.POW_BUFFER: return 6;
                case Opcode.MAX_SCALAR: return 10;
                case Opcode.MAX_BUFFER: return 8;
                case Opcode.COMPRESS_BUFFER: return 14;
                case Opcode._UNUSED_2C: return 2; // shouldn't get here
                case Opcode.LERP_BUFFER: return 8;
                case Opcode.LERP_BUFFER_2: return 10;
                case Opcode.LERP_SCALAR: return 10;
                case Opcode.HARD_CLIP_BUFFER_BUFFER: return 6;
                case Opcode.HARD_CLIP_BUFFER_SCALAR: return 6;
                case Opcode.HARD_CLIP_SCALAR_SCALAR: return 8;
                case Opcode.SOFT_CLIP_BUFFER_BUFFER: return 6;
                case Opcode.SOFT_CLIP_BUFFER_SCALAR: return 6;
                case Opcode.SOFT_CLIP_SCALAR_SCALAR: return 8;
                case Opcode.ENVELOPE_FOLLOWER_BUFFER: return 10;
                case Opcode.ENVELOPE_FOLLOWER_SCALAR: return 12;
                case Opcode.BiquadCoefficients_LowPass_1: return 16;
                case Opcode.BiquadCoefficients_HighPass_1: return 16;
                case Opcode.BiquadCoefficients_BandPass: return 16;
                case Opcode.BiquadCoefficients_BandStop: return 16;
                case Opcode.BiquadCoefficients_LowPass_2: return 16;
                case Opcode.BiquadCoefficients_HighPass_2: return 16;
                case Opcode.BiquadCoefficients_PeakingEQ: return 18;
                case Opcode.BiquadProcess_2Pole: return 16;
                case Opcode.BiquadProcess_4Pole: return 16;
                case Opcode.OnePole_LPF_BUFFER_BUFFER: return 8;
                case Opcode.OnePole_LPF_BUFFER_SCALAR: return 8;
                case Opcode.OnePole_LPF_SCALAR_SCALAR: return 10;
                case Opcode.OnePole_HPF_BUFFER_BUFFER: return 8;
                case Opcode.OnePole_HPF_BUFFER_SCALAR: return 8;
                case Opcode.OnePole_HPF_SCALAR_SCALAR: return 10;
                case Opcode.OSC_RAMP_BUFFER_BUFFER: return 6;
                case Opcode.OSC_RAMP_BUFFER_SCALAR: return 8;
                case Opcode.OSC_RAMP_SCALAR: return 8;
                case Opcode.SINE_BUFFER: return 4;
                case Opcode.SINE: return 6;
                case Opcode.COSINE_BUFFER: return 4;
                case Opcode.COSINE: return 6;
                case Opcode.TRIANGLE_BUFFER: return 4;
                case Opcode.TRIANGLE: return 6;
                case Opcode.SQUARE_BUFFER: return 4;
                case Opcode.SQUARE: return 6;
                case Opcode.SAW_BUFFER: return 4;
                case Opcode.SAW: return 6;
                case Opcode.TRIGGER_LATCH: return 10;

                case Opcode.ENVELOPE_GEN__R_LINEAR_T_INTERRUPTIBLE:
                case Opcode.ENVELOPE_GEN__R_LINEAR_T_ONE_SHOT:
                case Opcode.ENVELOPE_GEN__R_LINEAR_T_RETRIGGER:
                case Opcode.ENVELOPE_GEN__R_EXP_T_INTERRUPTIBLE:
                case Opcode.ENVELOPE_GEN__R_EXP_T_ONE_SHOT:
                case Opcode.ENVELOPE_GEN__R_EXP_T_RETRIGGER:
                    return outputs == 2 ? 22 : 20;

                case Opcode.TIMED_TRIGGER__T_INTERRUPTIBLE:
                case Opcode.TIMED_TRIGGER__T_ONE_SHOT:
                case Opcode.TIMED_TRIGGER__T_RETRIGGER:
                    return 26;

                case Opcode.READ_VARIABLE: return 6;
                case Opcode.STOP: return 4;

                case Opcode.READ_INPUT_BUFFER0:
                case Opcode.READ_INPUT_BUFFER1:
                case Opcode.READ_INPUT_BUFFER2:
                case Opcode.READ_INPUT_BUFFER3:
                case Opcode.READ_INPUT_BUFFER4:
                case Opcode.READ_INPUT_BUFFER5:
                case Opcode.READ_INPUT_BUFFER6:
                case Opcode.READ_INPUT_BUFFER7:
                    return 4;

                case Opcode.NOTE_TO_FREQUENCY_SCALAR: return 6;
                case Opcode.NOTE_TO_FREQUENCY_BUFFER: return 4;
                case Opcode.SAMPLE_AND_HOLD: return 10;
                case Opcode.DECIMATE_BUFFER: return 10;

                case Opcode.COUNTER:
                case Opcode.COUNTER_TRIGGER:
                    return 14;

                case Opcode.GATE_BUFFER_BUFFER: return 6;
                case Opcode.GATE_BUFFER_SCALAR: return 6;
                case Opcode.GATE_SCALAR_SCALAR: return 8;

                case Opcode.SMALL_DELAY_FRAC:
                case Opcode.SMALL_DELAY_NON_INTERP:
                    return 4 + (inputs == 3 ? 6 : 4);

                case Opcode.SMALL_DELAY_FRAC_FEEDBACK:
                case Opcode.SMALL_DELAY_NON_INTERP_FEEDBACK:
                    return 10;

                case Opcode.TRIGGER_DIFF: return 10;
                case Opcode.RANDOM_ON_INIT: return 10;
                case Opcode.FILL_BUFFER: return 6;
                case Opcode.AWProcess: return 10;
                case Opcode.LERP_BUFFER_BUFFER: return 8;

                case Opcode.BiquadCoefficients_HighShelf_1:
                case Opcode.BiquadCoefficients_HighShelf_2:
                case Opcode.BiquadCoefficients_LowShelf_1:
                case Opcode.BiquadCoefficients_LowShelf_2:
                    return 18;

                case Opcode.SWITCH_NORM_BUFFER:
                case Opcode.SWITCH_INDEX_BUFFER:
                case Opcode.SWITCH_LERP_BUFFER:
                case Opcode.SWITCH_EQUAL_POWER_BUFFFER:
                    return 6 + (inputs - 2) * 2;

                case Opcode.SWITCH_NORM_SCALAR:
                case Opcode.SWITCH_INDEX_SCALAR:
                case Opcode.SWITCH_LERP_SCALAR:
                case Opcode.SWITCH_EQUAL_POWER_SCALAR:
                    return 6 + (inputs - 1) * 2;

                case Opcode.AllpassProcess_BUFFER_SCALAR: return 8;
                case Opcode.AllpassProcess_BUFFER_BUFFER: return 8;

                case Opcode.FINISH: return 2;
            }

            throw new NotImplementedException($"SizeOf '{opcode}' is not implemented");
        }

        public class AssembleResult
        {
            public byte[] Bytecode { get; set; } = Array.Empty<byte>();
            public int BuffersCount { get; set; }
            public int RegistersCount { get; set; }
            public int StateBlocksCount { get; set; }
            public int VariablesCount { get; set; }
            public List<float> Constants { get; set; } = new List<float>();
        }

        public static AssembleResult Assemble(string assembly, Dat10SynthVariable[] variables, Action<string, int> onError = null)
        {
            var result = new AssembleResult();

            using (var reader = new StringReader(assembly))
            using (var mem = new MemoryStream())
            using (var bw = new BinaryWriter(mem))
            {
                string line;
                int lineNumber = 1;
                while ((line = reader.ReadLine()) != null)
                {
                    var inst = Parse(line, result, variables, msg => onError?.Invoke(msg, lineNumber));
                    inst?.Encode(bw);
                    lineNumber++;
                }

                const int Align = 4;
                var padding = (Align - (mem.Length % Align)) % Align;
                if (padding > 0) bw.Write(new byte[padding]);

                result.Bytecode = mem.ToArray();
                return result;
            }
        }

        private static Instruction? Parse(string line, AssembleResult result, Dat10SynthVariable[] variables, Action<string> onError)
        {
            var commentStart = line.IndexOf(';');
            if (commentStart != -1)
            {
                // remove comment
                line = line.Substring(0, commentStart);
            }

            line = line.Trim();
            if (line.Length == 0)
            {
                return null;
            }

            var opcodeName = line.Substring(0, line.TakeWhile(c => !char.IsWhiteSpace(c)).Count());

            if (!Enum.TryParse<Opcode>(opcodeName, out var opcode))
            {
                onError($"Unknown opcode '{opcodeName}'");
                return null;
            }

            if (line.Length - opcodeName.Length <= 0)
            {
                onError("Missing input/output parameters");
                return null;
            }

            line = line.Substring(opcodeName.Length);
            var parts = line.Split(new[] { "=>" }, StringSplitOptions.None);
            if (parts.Length != 2)
            {
                onError("Missing input or output parameters");
                return null;
            }

            var inputs = parts[0].Split(',').Select(s => s.Trim()).Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();

            var stateBlockEnd = parts[1].LastIndexOf(']');
            var stateBlockStart = parts[1].IndexOf('[');

            if (stateBlockStart > stateBlockEnd)
            {
                onError("Mismatched state block brackets");
                return null;
            }

            if (stateBlockEnd != -1 && stateBlockEnd != parts[1].Length - 1)
            {
                onError($"Stuff after state block... '{parts[1].Substring(stateBlockEnd + 1)}'");
                return null;
            }

            var stateBlockUsed = false;
            var hasStateBlock = stateBlockStart != -1;
            var stateBlockStr = hasStateBlock ? parts[1].Substring(stateBlockStart + 1, stateBlockEnd - stateBlockStart - 1) : null;

            var outputs = parts[1].Substring(0, hasStateBlock ? stateBlockStart : parts[1].Length)
                                  .Split(',').Select(s => s.Trim()).Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();

            var currInputIndex = 0;
            var currOutputIndex = 0;
            var parameters = new List<Parameter>();

            void Param(ParameterType type)
            {
                var currInput = Parameter.IsInputType(type) && currInputIndex < inputs.Length ? inputs[currInputIndex] : null;
                var currOutput = Parameter.IsOutputType(type) && currOutputIndex < outputs.Length ? outputs[currOutputIndex] : null;
                ushort paramValue = 0xFFFF;

                bool parseParameter = true;
                if (Parameter.IsInputType(type) && currInput == null)
                {
                    onError($"Missing input parameter #{currInputIndex}, expected {Parameter.TypeToStringReadable(type)}");
                    parseParameter = false;
                }

                if (Parameter.IsOutputType(type) && currOutput == null)
                {
                    onError($"Missing output parameter #{currOutputIndex}, expected {Parameter.TypeToStringReadable(type)}");
                    parseParameter = false;
                }

                if (parseParameter)
                {
                    switch (type)
                    {
                        case ParameterType.InputBuffer: paramValue = ParseBuffer(currInput, result, onError); break;
                        case ParameterType.InputRegister: paramValue = ParseRegister(currInput, result, onError); break;
                        case ParameterType.InputScalar:
                            paramValue = currInput[0] == 'R' ?
                                            ParseRegister(currInput, result, onError) :
                                            ParseConstant(currInput, result, onError);
                            break;
                        case ParameterType.InputVariable: paramValue = ParseVariable(currInput, variables, result, onError); break;
                        case ParameterType.OutputBuffer: paramValue = ParseBuffer(currOutput, result, onError); break;
                        case ParameterType.OutputRegister: paramValue = ParseRegister(currOutput, result, onError); break;
                        case ParameterType.InputOutputBuffer:
                            if (currInput != currOutput)
                            {
                                onError($"Expected same input/output buffer: input = '{currInput}', output = '{currOutput}'");
                            }

                            paramValue = ParseBuffer(currInput, result, onError);
                            break;
                        case ParameterType.StateBlock:
                            byte stateBlockIndex = 0;
                            if (!hasStateBlock)
                            {
                                onError($"Opcode '{opcodeName}' requires a state block");
                            }
                            else
                            {
                                if (!byte.TryParse(stateBlockStr, out stateBlockIndex))
                                {
                                    onError($"Invalid state block: '{stateBlockStr}' cannot be parsed as an 8-bit integer");
                                }

                                if (stateBlockIndex >= MaxStateBlocks)
                                {
                                    onError($"Invalid state block: {stateBlockIndex} is out of bounds (valid range: 0 to {MaxStateBlocks - 1})");
                                }
                            }

                            result.StateBlocksCount = Math.Max(stateBlockIndex + 1, result.StateBlocksCount);
                            paramValue = stateBlockIndex;
                            stateBlockUsed = true;
                            break;
                        case ParameterType.Ignored:
                            // the game doesn't use this value, but existing synths use the same value as the first param
                            paramValue = parameters[0].Value;
                            break;
                        default: throw new NotImplementedException();
                    }
                }

                if (Parameter.IsInputType(type))
                {
                    currInputIndex++;
                }

                if (Parameter.IsOutputType(type))
                {
                    currOutputIndex++;
                }

                parameters.Add(new Parameter(type, paramValue));
            }

            bool IsInputScalar() => currInputIndex < inputs.Length && inputs[currInputIndex][0] != 'B';

            var numInputs = inputs.Length;
            var numOutputs = outputs.Length;

            if (opcode == Opcode.COPY_BUFFER || opcode == Opcode.COPY_REGISTER)
            {
                // count the ignored param as output
                numOutputs++;
            }

            HandleOpcode(opcode, numInputs, numOutputs, Param, IsInputScalar);

            if (!stateBlockUsed && hasStateBlock)
            {
                onError($"State block specified but not required by opcode '{opcodeName}'");
            }

            if (currInputIndex < inputs.Length)
            {
                onError($"Too many inputs for opcode '{opcode}'");
            }

            if (currOutputIndex < outputs.Length)
            {
                onError($"Too many outputs for opcode '{opcode}'");
            }

            return new Instruction
            {
                Opcode = opcode,
                InputsOutputs = opcode != Opcode.FINISH ? (byte)((numInputs << 4) | numOutputs) : (byte)0xFF,
                Parameters = parameters.ToArray(),
            };
        }

        private static ushort ParseVariable(string str, Dat10SynthVariable[] variables, AssembleResult result, Action<string> onError)
        {
            bool foundByName = false;
            byte varIndex = 0xFF;
            if (variables != null && variables.Length > 0)
            {
                try
                {
                    var nameHash = XmlMeta.GetHash(str);

                    for (int i = 0; i < variables.Length; i++)
                    {
                        if (variables[i].Name == nameHash)
                        {
                            foundByName = true;
                            varIndex = (byte)i;
                            break;
                        }
                    }
                }
                catch (Exception e) // XmlMeta.GetHash throws an exception if the hash is not a valid hex number
                {
                    onError($"Invalid variable name '{str}': {e.Message}");
                    return 0;
                }
            }

            if (!foundByName)
            {
                if (str[0] != 'V')
                {
                    onError($"Unknown variable '{str}'");
                    return 0;
                }

                var indexStr = str.Substring(1);
                if (!byte.TryParse(indexStr, out varIndex))
                {
                    onError($"Invalid variable: '{indexStr}' cannot be parsed as an 8-bit integer");
                    return 0;
                }
            }

            result.VariablesCount = Math.Max(varIndex + 1, result.VariablesCount);
            return (ushort)(0x300 | varIndex);
        }

        private static ushort ParseConstant(string str, AssembleResult result, Action<string> onError)
        {
            if (!FloatUtil.TryParse(str, out var constantValue))
            {
                onError($"Invalid constant: '{str}' cannot be parsed as a float");
                return 0;
            }

            byte constantId;
            if (constantValue == 0.0f)
            {
                constantId = 0;
            }
            else if (constantValue == 1.0f)
            {
                constantId = 1;
            }
            else
            {
                var constants = result.Constants;

                // This is not exactly how R* compiler handles constants. Sometimes it reuses constants and sometimes it doesn't,
                // here we will always reuse the constant, so it won't generate the exact same bytecode when reassembling
                var constantIndex = -1;
                for (int i = 0; i < constants.Count; i++)
                {
                    if (constants[i] == constantValue)
                    {
                        constantIndex = i;
                        break;
                    }
                }

                if (constantIndex == -1)
                {
                    constantIndex = constants.Count;
                    constants.Add(constantValue);
                }

                constantId = (byte)(constantIndex + 2);
            }

            return (ushort)(0x200 | constantId);
        }

        private static ushort ParseRegister(string str, AssembleResult result, Action<string> onError)
        {
            if (str[0] != 'R')
            {
                onError($"Expected a register, found '{str}'");
                return 0;
            }

            var indexStr = str.Substring(1);
            if (!byte.TryParse(indexStr, out var index))
            {
                onError($"Invalid register: '{indexStr}' cannot be parsed as an 8-bit integer");
                return 0;
            }

            if (index >= MaxRegisters)
            {
                // the synth 'dlc_xm_superweapon_xxx' from 'update\update.rpf\x64\audio\config\optamp.dat10.rel' uses 72 registers even
                // though it is above the hardcoded .exe limit, so don't fail to allow to re-assemble the file.
                // The game just ignores this synth and uses the one with the same name from 'dlcchristmas2017_amp.dat10'
                // onError($"Invalid register: {registerIndex} is out of bounds (max: {MaxRegisters})");
            }

            result.RegistersCount = Math.Max(index + 1, result.RegistersCount);
            return (ushort)(0x100 | index);
        }

        private static ushort ParseBuffer(string str, AssembleResult result, Action<string> onError)
        {
            if (str[0] != 'B')
            {
                onError($"Expected a buffer, found '{str}'");
                return 0;
            }

            var indexStr = str.Substring(1);
            if (!byte.TryParse(indexStr, out var index))
            {
                onError($"Invalid buffer: '{indexStr}' cannot be parsed as an 8-bit integer");
                return 0;
            }

            if (index >= MaxBuffers)
            {
                onError($"Invalid buffer: B{index} is out of bounds (valid range: B0 to B{MaxBuffers - 1})");
            }

            result.BuffersCount = Math.Max(index + 1, result.BuffersCount);
            return index;
        }

        public static Instruction Decode(BinaryReader bytecode)
        {
            var result = new Instruction();
            result.InputsOutputs = bytecode.ReadByte();
            result.Opcode = (Opcode)bytecode.ReadByte();
            var outputs = result.InputsOutputs & 0xF;
            var inputs = result.InputsOutputs >> 4;
            var parameters = new List<Parameter>(8);

            void Param(ParameterType type) => parameters.Add(new Parameter(type, bytecode.ReadUInt16()));
            bool IsInputScalar()
            {
                var inputVal = bytecode.ReadUInt16();
                bytecode.BaseStream.Seek(-sizeof(ushort), SeekOrigin.Current);
                return (inputVal & 0xFF00) != 0;
            }

            HandleOpcode(result.Opcode, result.NumberOfInputs, result.NumberOfOutputs, Param, IsInputScalar);

            result.Parameters = parameters.ToArray();
            return result;
        }

        private static void HandleOpcode(Opcode opcode, int inputs, int outputs, Action<ParameterType> cb, Func<bool> isInputScalar)
        {
            switch (opcode)
            {
                case Opcode.COPY_BUFFER:
                    cb(ParameterType.InputBuffer);
                    for (int i = 0; i < (outputs - 1); i++)
                    {
                        cb(ParameterType.OutputBuffer);
                    }
                    cb(ParameterType.Ignored); // not used by the game, same value as the input buffer
                    break;

                case Opcode.COPY_REGISTER:
                    cb(ParameterType.InputRegister);
                    for (int i = 0; i < (outputs - 1); i++)
                    {
                        cb(ParameterType.OutputRegister);
                    }
                    cb(ParameterType.Ignored); // not used by the game, same value as the input register
                    break;

                case Opcode.CONVERT_BUFFER_TO_DENORMALIZED:
                case Opcode.CONVERT_BUFFER_TO_NORMALIZED:
                    cb(ParameterType.InputOutputBuffer);
                    break;

                case Opcode.CONVERT_SCALAR_TO_DENORMALIZED:
                case Opcode.CONVERT_SCALAR_TO_NORMALIZED:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    break;

                case Opcode.FIRST_OF_BUFFER:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputBuffer);
                    break;

                case Opcode.MULTIPLY_BUFFER_BUFFER:
                case Opcode.SUM_BUFFER_BUFFER:
                case Opcode.SUBTRACT_BUFFER_BUFFER:
                case Opcode.DIVIDE_BUFFER_BUFFER:
                case Opcode.HARD_CLIP_BUFFER_BUFFER:
                case Opcode.SOFT_CLIP_BUFFER_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputBuffer);
                    break;

                case Opcode.MULTIPLY_BUFFER_SCALAR:
                case Opcode.SUM_BUFFER_SCALAR:
                case Opcode.SUBTRACT_BUFFER_SCALAR:
                case Opcode.DIVIDE_BUFFER_SCALAR:
                case Opcode.HARD_CLIP_BUFFER_SCALAR:
                case Opcode.SOFT_CLIP_BUFFER_SCALAR:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar);
                    break;

                case Opcode.SUBTRACT_SCALAR_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.Ignored); // not used by the game
                    break;

                case Opcode.MULTIPLY_SCALAR_SCALAR:
                case Opcode.SUM_SCALAR_SCALAR:
                case Opcode.SUBTRACT_SCALAR_SCALAR:
                case Opcode.DIVIDE_SCALAR_SCALAR:
                case Opcode.HARD_CLIP_SCALAR_SCALAR:
                case Opcode.SOFT_CLIP_SCALAR_SCALAR:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    break;

                case Opcode.RESCALE_BUFFER_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputBuffer); // original min
                    cb(ParameterType.InputBuffer); // original max
                    cb(ParameterType.InputBuffer); // new min
                    cb(ParameterType.InputBuffer); // new max
                    break;

                case Opcode.RESCALE_BUFFER_SCALAR:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar); // original min
                    cb(ParameterType.InputScalar); // original max
                    cb(ParameterType.InputScalar); // new min
                    cb(ParameterType.InputScalar); // new max
                    break;

                case Opcode.RESCALE_SCALAR_SCALAR:
                    cb(ParameterType.OutputRegister); // result
                    cb(ParameterType.InputScalar); // value
                    cb(ParameterType.InputScalar); // original min
                    cb(ParameterType.InputScalar); // original max
                    cb(ParameterType.InputScalar); // new min
                    cb(ParameterType.InputScalar); // new max
                    break;

                case Opcode.HARD_KNEE_SCALAR_SCALAR:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    break;

                case Opcode.NOISE:
                    cb(ParameterType.OutputBuffer);
                    break;

                case Opcode.RANDOM:
                    cb(ParameterType.OutputRegister); // result
                    cb(ParameterType.InputScalar); // next: if >= 1.0 then generate a new random value; else return the last value
                    cb(ParameterType.InputScalar); // min
                    cb(ParameterType.InputScalar); // max
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.ABS_BUFFER:
                case Opcode.FLOOR_BUFFER:
                case Opcode.CEIL_BUFFER:
                case Opcode.ROUND_BUFFER:
                case Opcode.SIGN_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    break;

                case Opcode.ABS_SCALAR:
                case Opcode.FLOOR_SCALAR:
                case Opcode.CEIL_SCALAR:
                case Opcode.ROUND_SCALAR:
                case Opcode.SIGN_SCALAR:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    break;

                case Opcode.HARD_KNEE_BUFFER:
                case Opcode.MODULO_BUFFER:
                case Opcode.POW_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    if (isInputScalar())
                    {
                        cb(ParameterType.InputScalar);
                    }
                    else
                    {
                        cb(ParameterType.InputBuffer);
                    }
                    break;

                case Opcode.MODULO_SCALAR:
                case Opcode.POW_SCALAR:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    break;

                case Opcode.MAX_SCALAR:
                    cb(ParameterType.OutputRegister); // result: max value between the absolute value of the input and the stored value
                    cb(ParameterType.InputScalar); // input
                    cb(ParameterType.InputScalar); // trigger: if >= 1.0 then compare to 0.0 instead of stored value
                    cb(ParameterType.StateBlock);  // stores the last result value
                    break;

                case Opcode.MAX_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.COMPRESS_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode._UNUSED_2C: // shouldn't get here
                    break;

                case Opcode.LERP_BUFFER:
                    cb(ParameterType.InputOutputBuffer); // t
                    cb(ParameterType.InputScalar); // min
                    cb(ParameterType.InputScalar); // max
                    break;

                case Opcode.LERP_BUFFER_2:
                    cb(ParameterType.OutputBuffer); // this buffer should be the same as one of the input buffers
                    cb(ParameterType.InputScalar); // t
                    cb(ParameterType.InputBuffer);
                    cb(ParameterType.InputBuffer);
                    break;

                case Opcode.LERP_SCALAR:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar); // t
                    cb(ParameterType.InputScalar); // min
                    cb(ParameterType.InputScalar); // max
                    break;

                case Opcode.ENVELOPE_FOLLOWER_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.ENVELOPE_FOLLOWER_SCALAR:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.BiquadCoefficients_LowPass_1:  // bool = false
                case Opcode.BiquadCoefficients_HighPass_1: // bool = false
                case Opcode.BiquadCoefficients_BandPass:
                case Opcode.BiquadCoefficients_BandStop:
                case Opcode.BiquadCoefficients_LowPass_2:  // bool = true
                case Opcode.BiquadCoefficients_HighPass_2: // bool = true
                    cb(ParameterType.OutputRegister); // b0
                    cb(ParameterType.OutputRegister); // b1
                    cb(ParameterType.OutputRegister); // b2
                    cb(ParameterType.OutputRegister); // a1
                    cb(ParameterType.OutputRegister); // a2
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    break;

                case Opcode.BiquadCoefficients_PeakingEQ:
                    cb(ParameterType.OutputRegister); // b0
                    cb(ParameterType.OutputRegister); // b1
                    cb(ParameterType.OutputRegister); // b2
                    cb(ParameterType.OutputRegister); // a1
                    cb(ParameterType.OutputRegister); // a2
                    cb(ParameterType.InputScalar);    // centerFrequency
                    cb(ParameterType.InputScalar);    // unkFrequency
                    cb(ParameterType.InputScalar);    // gain
                    break;

                case Opcode.BiquadProcess_2Pole:
                case Opcode.BiquadProcess_4Pole:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar); // b0
                    cb(ParameterType.InputScalar); // b1
                    cb(ParameterType.InputScalar); // b2
                    cb(ParameterType.InputScalar); // a1
                    cb(ParameterType.InputScalar); // a2
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.OnePole_LPF_BUFFER_BUFFER:
                case Opcode.OnePole_HPF_BUFFER_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputBuffer);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.OnePole_LPF_BUFFER_SCALAR:
                case Opcode.OnePole_HPF_BUFFER_SCALAR:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.OnePole_LPF_SCALAR_SCALAR:
                case Opcode.OnePole_HPF_SCALAR_SCALAR:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.OSC_RAMP_BUFFER_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.OSC_RAMP_BUFFER_SCALAR:
                    cb(ParameterType.OutputBuffer);
                    cb(ParameterType.InputScalar); // frequency
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.OSC_RAMP_SCALAR:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.SINE_BUFFER:
                case Opcode.COSINE_BUFFER:
                case Opcode.TRIANGLE_BUFFER:
                case Opcode.SQUARE_BUFFER:
                case Opcode.SAW_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    break;

                case Opcode.SINE:
                case Opcode.COSINE:
                case Opcode.TRIANGLE:
                case Opcode.SQUARE:
                case Opcode.SAW:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    break;

                case Opcode.TRIGGER_LATCH:
                    cb(ParameterType.OutputRegister);
                    if (isInputScalar())
                    {
                        cb(ParameterType.InputScalar);
                        cb(ParameterType.InputScalar);
                    }
                    else
                    {
                        cb(ParameterType.InputBuffer);
                        if (isInputScalar())
                        {
                            cb(ParameterType.InputScalar);
                        }
                        else
                        {
                            cb(ParameterType.InputBuffer);
                        }
                    }
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.ENVELOPE_GEN__R_LINEAR_T_INTERRUPTIBLE:
                case Opcode.ENVELOPE_GEN__R_LINEAR_T_ONE_SHOT:
                case Opcode.ENVELOPE_GEN__R_LINEAR_T_RETRIGGER:
                case Opcode.ENVELOPE_GEN__R_EXP_T_INTERRUPTIBLE:
                case Opcode.ENVELOPE_GEN__R_EXP_T_ONE_SHOT:
                case Opcode.ENVELOPE_GEN__R_EXP_T_RETRIGGER:
                    cb(ParameterType.OutputBuffer); // envelope
                    if (outputs == 2)
                    {
                        cb(ParameterType.OutputRegister); // finished
                    }
                    cb(ParameterType.InputScalar); // predelay
                    cb(ParameterType.InputScalar); // attack
                    cb(ParameterType.InputScalar); // decay
                    cb(ParameterType.InputScalar); // sustain
                    cb(ParameterType.InputScalar); // hold
                    cb(ParameterType.InputScalar); // release
                    cb(ParameterType.InputScalar); // trigger
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.TIMED_TRIGGER__T_INTERRUPTIBLE:
                case Opcode.TIMED_TRIGGER__T_ONE_SHOT:
                case Opcode.TIMED_TRIGGER__T_RETRIGGER:
                    cb(ParameterType.OutputRegister); // finished
                    cb(ParameterType.OutputRegister); // attack active
                    cb(ParameterType.OutputRegister); // decay active
                    cb(ParameterType.OutputRegister); // hold active
                    cb(ParameterType.OutputRegister); // release active
                    cb(ParameterType.InputScalar); // trigger
                    cb(ParameterType.InputScalar); // predelay
                    cb(ParameterType.InputScalar); // attack
                    cb(ParameterType.InputScalar); // decay
                    cb(ParameterType.InputScalar); // hold
                    cb(ParameterType.InputScalar); // release
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.READ_VARIABLE:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputVariable);
                    break;

                case Opcode.STOP:
                    cb(ParameterType.InputScalar); // trigger: if >= 1.0 then stop executing the synth
                    break;

                case Opcode.READ_INPUT_BUFFER0: // used for DSP effects
                case Opcode.READ_INPUT_BUFFER1:
                case Opcode.READ_INPUT_BUFFER2:
                case Opcode.READ_INPUT_BUFFER3:
                case Opcode.READ_INPUT_BUFFER4:
                case Opcode.READ_INPUT_BUFFER5:
                case Opcode.READ_INPUT_BUFFER6:
                case Opcode.READ_INPUT_BUFFER7:
                    cb(ParameterType.OutputBuffer);
                    break;

                case Opcode.NOTE_TO_FREQUENCY_SCALAR:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    break;

                case Opcode.NOTE_TO_FREQUENCY_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    break;

                case Opcode.SAMPLE_AND_HOLD:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar); // value
                    cb(ParameterType.InputScalar); // trigger: if >= 1.0 then store value; else return stored value
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.DECIMATE_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.COUNTER:
                case Opcode.COUNTER_TRIGGER:
                    cb(ParameterType.OutputRegister); // result: COUNTER: counter value
                                                      //         COUNTER_TRIGGER: when counter = 0 (due to zero or max params), returns 1; otherwise 0
                    cb(ParameterType.InputScalar); // zero:     if >= 1.0 then counter = 0
                    cb(ParameterType.InputScalar); // add:      if >= 1.0 then counter += 1
                    cb(ParameterType.InputScalar); // subtract: if >= 1.0 then counter -= 1
                    cb(ParameterType.InputScalar); // max:      if >= 0.0 && counter >= max then counter = 0
                    cb(ParameterType.StateBlock); // stores the counter
                    break;

                case Opcode.GATE_BUFFER_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputBuffer);
                    break;

                case Opcode.GATE_BUFFER_SCALAR:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar);
                    break;

                case Opcode.GATE_SCALAR_SCALAR:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    break;

                case Opcode.SMALL_DELAY_FRAC:
                case Opcode.SMALL_DELAY_NON_INTERP:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar);
                    if (inputs == 3)
                    {
                        // the game ignores this value and in the files it is always 0x200,
                        // but keep it to generate the exact same bytecode when reassembling
                        cb(ParameterType.InputScalar);
                    }
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.SMALL_DELAY_FRAC_FEEDBACK:
                case Opcode.SMALL_DELAY_NON_INTERP_FEEDBACK:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.TRIGGER_DIFF:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.RANDOM_ON_INIT: // like RANDOM, but only generates the random value once, then it always returns the same value
                    cb(ParameterType.OutputRegister); // result
                    cb(ParameterType.InputScalar); // min
                    cb(ParameterType.InputScalar); // max
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.FILL_BUFFER: // sets the whole buffer to the same value
                    cb(ParameterType.OutputBuffer); // dest
                    cb(ParameterType.InputScalar); // value
                    break;

                case Opcode.AWProcess:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputBuffer);
                    cb(ParameterType.InputBuffer);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.LERP_BUFFER_BUFFER:
                    cb(ParameterType.InputOutputBuffer); // t
                    cb(ParameterType.InputBuffer); // min
                    cb(ParameterType.InputBuffer); // max
                    break;

                case Opcode.BiquadCoefficients_HighShelf_1:
                case Opcode.BiquadCoefficients_HighShelf_2:
                case Opcode.BiquadCoefficients_LowShelf_1:
                case Opcode.BiquadCoefficients_LowShelf_2:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.InputScalar);
                    break;

                case Opcode.SWITCH_NORM_BUFFER:
                case Opcode.SWITCH_INDEX_BUFFER:
                case Opcode.SWITCH_LERP_BUFFER:
                case Opcode.SWITCH_EQUAL_POWER_BUFFFER:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar);
                    for (int i = 0; i < (inputs - 2); i++)
                    {
                        cb(ParameterType.InputBuffer);
                    }
                    break;

                case Opcode.SWITCH_NORM_SCALAR:
                case Opcode.SWITCH_INDEX_SCALAR:
                case Opcode.SWITCH_LERP_SCALAR:
                case Opcode.SWITCH_EQUAL_POWER_SCALAR:
                    cb(ParameterType.OutputRegister);
                    cb(ParameterType.InputScalar);
                    for (int i = 0; i < (inputs - 1); i++)
                    {
                        cb(ParameterType.InputScalar);
                    }
                    break;

                case Opcode.AllpassProcess_BUFFER_SCALAR:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputScalar);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.AllpassProcess_BUFFER_BUFFER:
                    cb(ParameterType.InputOutputBuffer);
                    cb(ParameterType.InputBuffer);
                    cb(ParameterType.StateBlock);
                    break;

                case Opcode.FINISH:
                    break;
            }
        }

        public struct Instruction
        {
            public byte InputsOutputs { get; set; }
            public Opcode Opcode { get; set; }
            public Parameter[] Parameters { get; set; }

            public int NumberOfInputs => InputsOutputs >> 4;
            public int NumberOfOutputs => InputsOutputs & 0xF;
            public int Size => SizeOf(Opcode, NumberOfInputs, NumberOfOutputs);

            public void Encode(BinaryWriter bw)
            {
                bw.Write(InputsOutputs);
                bw.Write((byte)Opcode);
                foreach (var p in Parameters)
                {
                    bw.Write(p.Value);
                }
            }

            public override string ToString()
            {
                return ToString(null, null);
            }

            public string ToString(float[] constants, Dat10SynthVariable[] variables)
            {
                var stateBlock = Parameters.Cast<Parameter?>().SingleOrDefault(p => p.Value.IsStateBlock);
                var inputsStr = string.Join(", ", Parameters.Where(p => p.IsInput).Select(p => p.ToString(constants, variables)));
                var outputsStr = string.Join(", ", Parameters.Where(p => p.IsOutput).Select(p => p.ToString(constants, variables))) +
                                    (stateBlock.HasValue ? " " + stateBlock.Value.ToString(constants, variables) : "");
                return $"{Opcode,-34} {inputsStr,-16} => {outputsStr}";
            }
        }

        public struct Parameter
        {
            public ParameterType Type { get; set; }
            public ushort Value { get; set; }

            public bool IsInput => IsInputType(Type);
            public bool IsOutput => IsOutputType(Type);
            public bool IsStateBlock => Type == ParameterType.StateBlock;

            public Parameter(ParameterType type, ushort value)
            {
                Value = value;
                Type = type;
            }

            public override string ToString()
            {
                return ToString(null, null);
            }

            public string ToString(float[] constants, Dat10SynthVariable[] variables)
            {
                switch (Type)
                {
                    case ParameterType.InputBuffer:
                    case ParameterType.OutputBuffer:
                    case ParameterType.InputOutputBuffer:
                        return $"B{Value}";
                    case ParameterType.InputScalar:
                        if ((Value & 0xFF00) == 0x100)
                        {
                            goto case ParameterType.InputRegister;
                        }
                        else
                        {
                            var v = Value & 0xFF;
                            switch (v)
                            {
                                case 0: return "0";
                                case 1: return "1";
                                default:
                                    var index = v - 2;
                                    return constants == null || index >= constants.Length ?
                                            $"C{index}" :
                                            FloatUtil.ToString(constants[index]);
                            }
                        }
                    case ParameterType.InputRegister:
                    case ParameterType.OutputRegister:
                        return $"R{Value & 0xFF}";
                    case ParameterType.InputVariable:
                        int varIndex = Value & 0xFF;
                        return variables == null || varIndex >= variables.Length ?
                                $"V{varIndex}" :
                                RelXml.HashString(variables[varIndex].Name);
                    case ParameterType.StateBlock:
                        return $"[{Value}]";
                    case ParameterType.Ignored:
                        return $"Ignored({Value})";
                }

                throw new NotImplementedException();
            }

            public static bool IsInputType(ParameterType type)
                => type == ParameterType.InputBuffer ||
                   type == ParameterType.InputRegister ||
                   type == ParameterType.InputScalar ||
                   type == ParameterType.InputVariable ||
                   type == ParameterType.InputOutputBuffer;

            public static bool IsOutputType(ParameterType type)
                => type == ParameterType.OutputBuffer ||
                   type == ParameterType.OutputRegister ||
                   type == ParameterType.InputOutputBuffer;

            // Returns a readable string representing the ParameterType, used in error messages
            public static string TypeToStringReadable(ParameterType type)
            {
                switch (type)
                {
                    case ParameterType.InputBuffer: return "input buffer";
                    case ParameterType.InputRegister: return "input register";
                    case ParameterType.InputScalar: return "input scalar";
                    case ParameterType.InputVariable: return "input variable";
                    case ParameterType.OutputBuffer: return "output buffer";
                    case ParameterType.OutputRegister: return "output register";
                    case ParameterType.InputOutputBuffer: return "input/output buffer";
                    case ParameterType.StateBlock: return "state block";
                    case ParameterType.Ignored: return "ignored";
                    default: return "unknown parameter type";
                }
            }
        }

        public enum ParameterType
        {
            InputBuffer,
            InputRegister,
            InputScalar,
            InputVariable,
            OutputBuffer,
            OutputRegister,
            InputOutputBuffer,
            StateBlock,
            Ignored,
        }

        public enum Opcode : byte
        {
            COPY_BUFFER = 0x00,
            COPY_REGISTER = 0x01,
            CONVERT_BUFFER_TO_DENORMALIZED = 0x02,
            CONVERT_SCALAR_TO_DENORMALIZED = 0x03,
            CONVERT_BUFFER_TO_NORMALIZED = 0x04,
            CONVERT_SCALAR_TO_NORMALIZED = 0x05,
            FIRST_OF_BUFFER = 0x06,
            MULTIPLY_BUFFER_BUFFER = 0x07,
            MULTIPLY_BUFFER_SCALAR = 0x08,
            MULTIPLY_SCALAR_SCALAR = 0x09,
            SUM_BUFFER_BUFFER = 0x0A,
            SUM_BUFFER_SCALAR = 0x0B,
            SUM_SCALAR_SCALAR = 0x0C,
            SUBTRACT_BUFFER_BUFFER = 0x0D,
            SUBTRACT_BUFFER_SCALAR = 0x0E,
            SUBTRACT_SCALAR_BUFFER = 0x0F,
            SUBTRACT_SCALAR_SCALAR = 0x10,
            DIVIDE_BUFFER_BUFFER = 0x11,
            DIVIDE_BUFFER_SCALAR = 0x12,
            DIVIDE_SCALAR_SCALAR = 0x13,
            RESCALE_BUFFER_BUFFER = 0x14,
            RESCALE_BUFFER_SCALAR = 0x15,
            RESCALE_SCALAR_SCALAR = 0x16,
            HARD_KNEE_BUFFER = 0x17,
            HARD_KNEE_SCALAR_SCALAR = 0x18,
            NOISE = 0x19,
            RANDOM = 0x1A,
            ABS_BUFFER = 0x1B,
            ABS_SCALAR = 0x1C,
            FLOOR_BUFFER = 0x1D,
            FLOOR_SCALAR = 0x1E,
            CEIL_BUFFER = 0x1F,
            CEIL_SCALAR = 0x20,
            ROUND_BUFFER = 0x21,
            ROUND_SCALAR = 0x22,
            SIGN_BUFFER = 0x23,
            SIGN_SCALAR = 0x24,
            MODULO_BUFFER = 0x25,
            MODULO_SCALAR = 0x26,
            POW_SCALAR = 0x27,
            POW_BUFFER = 0x28,
            MAX_SCALAR = 0x29,
            MAX_BUFFER = 0x2A,
            COMPRESS_BUFFER = 0x2B,
            _UNUSED_2C = 0x2C, // the game doesn't handle this opcode
            LERP_BUFFER = 0x2D,
            LERP_BUFFER_2 = 0x2E,
            LERP_SCALAR = 0x2F,
            HARD_CLIP_BUFFER_BUFFER = 0x30,
            HARD_CLIP_BUFFER_SCALAR = 0x31,
            HARD_CLIP_SCALAR_SCALAR = 0x32,
            SOFT_CLIP_BUFFER_BUFFER = 0x33,
            SOFT_CLIP_BUFFER_SCALAR = 0x34,
            SOFT_CLIP_SCALAR_SCALAR = 0x35,
            ENVELOPE_FOLLOWER_BUFFER = 0x36,
            ENVELOPE_FOLLOWER_SCALAR = 0x37,
            BiquadCoefficients_LowPass_1 = 0x38,
            BiquadCoefficients_HighPass_1 = 0x39,
            BiquadCoefficients_BandPass = 0x3A,
            BiquadCoefficients_BandStop = 0x3B,
            BiquadCoefficients_LowPass_2 = 0x3C,
            BiquadCoefficients_HighPass_2 = 0x3D,
            BiquadCoefficients_PeakingEQ = 0x3E,
            BiquadProcess_2Pole = 0x3F,
            BiquadProcess_4Pole = 0x40,
            OnePole_LPF_BUFFER_BUFFER = 0x41,
            OnePole_LPF_BUFFER_SCALAR = 0x42,
            OnePole_LPF_SCALAR_SCALAR = 0x43,
            OnePole_HPF_BUFFER_BUFFER = 0x44,
            OnePole_HPF_BUFFER_SCALAR = 0x45,
            OnePole_HPF_SCALAR_SCALAR = 0x46,
            OSC_RAMP_BUFFER_BUFFER = 0x47,
            OSC_RAMP_BUFFER_SCALAR = 0x48,
            OSC_RAMP_SCALAR = 0x49,
            SINE_BUFFER = 0x4A,
            SINE = 0x4B,
            COSINE_BUFFER = 0x4C,
            COSINE = 0x4D,
            TRIANGLE_BUFFER = 0x4E,
            TRIANGLE = 0x4F,
            SQUARE_BUFFER = 0x50,
            SQUARE = 0x51,
            SAW_BUFFER = 0x52,
            SAW = 0x53,
            TRIGGER_LATCH = 0x54,
            // R = release type, T = trigger mode
            ENVELOPE_GEN__R_LINEAR_T_INTERRUPTIBLE = 0x55,  // R = 0, T = 2
            ENVELOPE_GEN__R_LINEAR_T_ONE_SHOT = 0x56,       // R = 0, T = 0
            ENVELOPE_GEN__R_LINEAR_T_RETRIGGER = 0x57,      // R = 0, T = 1
            ENVELOPE_GEN__R_EXP_T_INTERRUPTIBLE = 0x58,     // R = 1, T = 2
            ENVELOPE_GEN__R_EXP_T_ONE_SHOT = 0x59,          // R = 1, T = 0
            ENVELOPE_GEN__R_EXP_T_RETRIGGER = 0x5A,         // R = 1, T = 1
            // T = trigger mode
            TIMED_TRIGGER__T_INTERRUPTIBLE = 0x5B,  // T = 2
            TIMED_TRIGGER__T_ONE_SHOT = 0x5C,       // T = 0
            TIMED_TRIGGER__T_RETRIGGER = 0x5D,      // T = 1
            READ_VARIABLE = 0x5E,
            STOP = 0x5F,
            READ_INPUT_BUFFER0 = 0x60,
            READ_INPUT_BUFFER1 = 0x61,
            READ_INPUT_BUFFER2 = 0x62,
            READ_INPUT_BUFFER3 = 0x63,
            READ_INPUT_BUFFER4 = 0x64,
            READ_INPUT_BUFFER5 = 0x65,
            READ_INPUT_BUFFER6 = 0x66,
            READ_INPUT_BUFFER7 = 0x67,
            NOTE_TO_FREQUENCY_SCALAR = 0x68,
            NOTE_TO_FREQUENCY_BUFFER = 0x69,
            SAMPLE_AND_HOLD = 0x6A,
            DECIMATE_BUFFER = 0x6B,
            COUNTER = 0x6C,
            COUNTER_TRIGGER = 0x6D,
            GATE_BUFFER_BUFFER = 0x6E,
            GATE_BUFFER_SCALAR = 0x6F,
            GATE_SCALAR_SCALAR = 0x70,
            SMALL_DELAY_FRAC = 0x71,
            SMALL_DELAY_NON_INTERP = 0x72,
            SMALL_DELAY_FRAC_FEEDBACK = 0x73,
            SMALL_DELAY_NON_INTERP_FEEDBACK = 0x74,
            TRIGGER_DIFF = 0x75,
            RANDOM_ON_INIT = 0x76,
            FILL_BUFFER = 0x77,
            AWProcess = 0x78,
            LERP_BUFFER_BUFFER = 0x79,
            BiquadCoefficients_HighShelf_1 = 0x7A,
            BiquadCoefficients_HighShelf_2 = 0x7B,
            BiquadCoefficients_LowShelf_1 = 0x7C,
            BiquadCoefficients_LowShelf_2 = 0x7D,
            SWITCH_NORM_BUFFER = 0x7E,
            SWITCH_INDEX_BUFFER = 0x7F,
            SWITCH_LERP_BUFFER = 0x80,
            SWITCH_EQUAL_POWER_BUFFFER = 0x81,
            SWITCH_NORM_SCALAR = 0x82,
            SWITCH_INDEX_SCALAR = 0x83,
            SWITCH_LERP_SCALAR = 0x84,
            SWITCH_EQUAL_POWER_SCALAR = 0x85,
            AllpassProcess_BUFFER_SCALAR = 0x86,
            AllpassProcess_BUFFER_BUFFER = 0x87,

            FINISH = 0xFF,
        }
    }


    #endregion




    #region dat15


    public enum Dat15RelType : byte
    {
        Patch = 0,//patch
        Unk1 = 1,
        Scene = 2,//scene
        Group = 3,//group
        GroupList = 4,//group list
        Unk5 = 5,
        Unk6 = 6,
        Unk7 = 7,
        Unk8 = 8,
        GroupMap = 9,//group map
    }

    [TC(typeof(EXP))] public class Dat15RelData : RelData
    {
        public Dat15RelType Type { get; set; }
        public uint NameTableOffset { get; set; }
        public FlagsUint Flags { get; set; }

        public Dat15RelData(RelFile rel) : base(rel) { }
        public Dat15RelData(RelFile rel, Dat15RelType type) : base(rel)
        {
            Type = type;
            TypeID = (byte)type;
        }
        public Dat15RelData(RelData d, BinaryReader br) : base(d)
        {
            Type = (Dat15RelType)TypeID;

            br.BaseStream.Position = 0; //1 byte was read already (TypeID)

            NameTableOffset = ((br.ReadUInt32() >> 8) & 0xFFFFFF);
            Flags = br.ReadUInt32();
        }

        public void WriteTypeAndOffsetAndFlags(BinaryWriter bw)
        {
            var val = ((NameTableOffset & 0xFFFFFF) << 8) + TypeID;
            bw.Write(val);
            bw.Write(Flags);
        }

        public override string ToString()
        {
            return GetBaseString() + ": " + Type.ToString();
        }
    }

    [TC(typeof(EXP))] public class Dat15PatchItem : IMetaXmlItem
    {
        public MetaHash Category { get; set; }
        public short Volume { get; set; }
        public byte Unk03 { get; set; }
        public short LPFCutoff { get; set; }
        public short HPFCutoff { get; set; }
        public short Unk08 { get; set; }
        public float Unk09 { get; set; }
        public byte Unk10 { get; set; }
        public float Unk11 { get; set; }

        public Dat15PatchItem()
        { }
        public Dat15PatchItem(BinaryReader br)
        {
            Category = br.ReadUInt32();
            Volume = br.ReadInt16();
            Unk03 = br.ReadByte();
            LPFCutoff = br.ReadInt16();
            HPFCutoff = br.ReadInt16();
            Unk08 = br.ReadInt16();
            Unk09 = br.ReadSingle();
            Unk10 = br.ReadByte();
            Unk11 = br.ReadSingle();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Category);
            bw.Write(Volume);
            bw.Write(Unk03);
            bw.Write(LPFCutoff);
            bw.Write(HPFCutoff);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Category", RelXml.HashString(Category));
            RelXml.ValueTag(sb, indent, "Volume", Volume.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "LPFCutoff", LPFCutoff.ToString());
            RelXml.ValueTag(sb, indent, "HPFCutoff", HPFCutoff.ToString());
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", FloatUtil.ToString(Unk09));
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.ValueTag(sb, indent, "Unk11", FloatUtil.ToString(Unk11));
        }
        public void ReadXml(XmlNode node)
        {
            Category = XmlRel.GetHash(Xml.GetChildInnerText(node, "Category"));
            Volume = (short)Xml.GetChildIntAttribute(node, "Volume", "value");
            Unk03 = (byte)Xml.GetChildUIntAttribute(node, "Unk03", "value");
            LPFCutoff = (short)Xml.GetChildIntAttribute(node, "LPFCutoff", "value");
            HPFCutoff = (short)Xml.GetChildIntAttribute(node, "HPFCutoff", "value");
            Unk08 = (short)Xml.GetChildIntAttribute(node, "Unk08", "value");
            Unk09 = Xml.GetChildFloatAttribute(node, "Unk09", "value");
            Unk10 = (byte)Xml.GetChildIntAttribute(node, "Unk10", "value");
            Unk11 = Xml.GetChildFloatAttribute(node, "Unk11", "value");
        }
        public override string ToString()
        {
            return Category.ToString() + ": " + 
                Volume.ToString() + ", " +
                Unk03.ToString() + ", " +
                LPFCutoff.ToString() + ", " +
                HPFCutoff.ToString() + ", " +
                Unk08.ToString() + ", " +
                Unk09.ToString() + ", " +
                Unk10.ToString() + ", " +
                Unk11.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat15Patch : Dat15RelData
    {
        public short FadeIn { get; set; }
        public short FadeOut { get; set; }
        public float PreDelay { get; set; }
        public float Duration { get; set; }
        public MetaHash ApplyFactorCurve { get; set; }
        public MetaHash ApplyVariable { get; set; }
        public float ApplySmoothRate { get; set; }
        public byte ItemCount { get; set; }
        public Dat15PatchItem[] Items { get; set; }

        public Dat15Patch(RelFile rel) : base(rel)
        {
            Type = Dat15RelType.Patch;
            TypeID = (byte)Type;
        }
        public Dat15Patch(RelData d, BinaryReader br) : base(d, br)
        {
            FadeIn = br.ReadInt16();
            FadeOut = br.ReadInt16();
            PreDelay = br.ReadSingle();
            Duration = br.ReadSingle();
            ApplyFactorCurve = br.ReadUInt32();
            ApplyVariable = br.ReadUInt32();
            ApplySmoothRate = br.ReadSingle();
            ItemCount = br.ReadByte();
            Items = new Dat15PatchItem[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat15PatchItem(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(FadeIn);
            bw.Write(FadeOut);
            bw.Write(PreDelay);
            bw.Write(Duration);
            bw.Write(ApplyFactorCurve);
            bw.Write(ApplyVariable);
            bw.Write(ApplySmoothRate);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "FadeIn", FadeIn.ToString());
            RelXml.ValueTag(sb, indent, "FadeOut", FadeOut.ToString());
            RelXml.ValueTag(sb, indent, "PreDelay", FloatUtil.ToString(PreDelay));
            RelXml.ValueTag(sb, indent, "Duration", FloatUtil.ToString(Duration));
            RelXml.StringTag(sb, indent, "ApplyFactorCurve", RelXml.HashString(ApplyFactorCurve));
            RelXml.StringTag(sb, indent, "ApplyVariable", RelXml.HashString(ApplyVariable));
            RelXml.ValueTag(sb, indent, "ApplySmoothRate", FloatUtil.ToString(ApplySmoothRate));
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            FadeIn = (short)Xml.GetChildIntAttribute(node, "FadeIn", "value");
            FadeOut = (short)Xml.GetChildIntAttribute(node, "FadeOut", "value");
            PreDelay = Xml.GetChildFloatAttribute(node, "PreDelay", "value");
            Duration = Xml.GetChildFloatAttribute(node, "Duration", "value");
            ApplyFactorCurve = XmlRel.GetHash(Xml.GetChildInnerText(node, "ApplyFactorCurve"));
            ApplyVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "ApplyVariable"));
            ApplySmoothRate = Xml.GetChildFloatAttribute(node, "ApplySmoothRate", "value");
            Items = XmlRel.ReadItemArray<Dat15PatchItem>(node, "Items");
            ItemCount = (byte)(Items?.Length ?? 0);
        }
        public override MetaHash[] GetCategoryHashes()
        {
            var list = new List<MetaHash>();
            if (Items != null)
            {
                foreach (var item in Items)
                {
                    list.Add(item.Category);
                }
            }
            return list.ToArray();
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { ApplyFactorCurve };
        }
    }
    [TC(typeof(EXP))] public class Dat15Unk1 : Dat15RelData
    {
        public byte ItemCount { get; set; }
        public Dat151HashPair[] Items { get; set; }//name hash, scene

        public Dat15Unk1(RelFile rel) : base(rel)
        {
            Type = Dat15RelType.Unk1;
            TypeID = (byte)Type;
        }
        public Dat15Unk1(RelData d, BinaryReader br) : base(d, br)
        {
            ItemCount = br.ReadByte();
            Items = new Dat151HashPair[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151HashPair(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Items = XmlRel.ReadItemArray<Dat151HashPair>(node, "Items");
            ItemCount = (byte)(Items?.Length ?? 0);
        }
        public override MetaHash[] GetMixerHashes()
        {
            var list = new List<MetaHash>();
            if (Items != null)
            {
                foreach (var item in Items)
                {
                    list.Add(item.Hash1);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat15SceneItem : IMetaXmlItem
    {
        public MetaHash Patch { get; set; }
        public MetaHash Group { get; set; }

        public Dat15SceneItem()
        { }
        public Dat15SceneItem(BinaryReader br)
        {
            Patch = br.ReadUInt32();
            Group = br.ReadUInt32();
        }
        public void Write(BinaryWriter bw)
        {
            bw.Write(Patch);
            bw.Write(Group);
        }
        public void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.StringTag(sb, indent, "Patch", RelXml.HashString(Patch));
            RelXml.StringTag(sb, indent, "Group", RelXml.HashString(Group));
        }
        public void ReadXml(XmlNode node)
        {
            Patch = XmlRel.GetHash(Xml.GetChildInnerText(node, "Patch"));
            Group = XmlRel.GetHash(Xml.GetChildInnerText(node, "Group"));
        }
        public override string ToString()
        {
            return Patch.ToString() + ": " + Group.ToString();
        }
    }
    [TC(typeof(EXP))] public class Dat15Scene : Dat15RelData
    {
        public MetaHash Unk01 { get; set; }//0
        public byte ItemCount { get; set; }
        public Dat15SceneItem[] Items { get; set; }

        public Dat15Scene(RelFile rel) : base(rel)
        {
            Type = Dat15RelType.Scene;
            TypeID = (byte)Type;
        }
        public Dat15Scene(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            ItemCount = br.ReadByte();
            Items = new Dat15SceneItem[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat15SceneItem(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(Unk01);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Items = XmlRel.ReadItemArray<Dat15SceneItem>(node, "Items");
            ItemCount = (byte)(Items?.Length ?? 0);
        }
        public override MetaHash[] GetMixerHashes()
        {
            var list = new List<MetaHash>();
            if (Items != null)
            {
                foreach (var item in Items)
                {
                    list.Add(item.Patch);
                    list.Add(item.Group);
                }
            }
            return list.ToArray();
        }
    }
    [TC(typeof(EXP))] public class Dat15Group : Dat15RelData
    {
        public uint ReferenceCount { get; set; }//0
        public float FadeTime { get; set; }
        public MetaHash Map { get; set; }

        public Dat15Group(RelFile rel) : base(rel)
        {
            Type = Dat15RelType.Group;
            TypeID = (byte)Type;
        }
        public Dat15Group(RelData d, BinaryReader br) : base(d, br)
        {
            ReferenceCount = br.ReadUInt32();
            FadeTime = br.ReadSingle();
            Map = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(ReferenceCount);
            bw.Write(FadeTime);
            bw.Write(Map);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "ReferenceCount", ReferenceCount.ToString());
            RelXml.ValueTag(sb, indent, "FadeTime", FloatUtil.ToString(FadeTime));
            RelXml.StringTag(sb, indent, "Map", RelXml.HashString(Map));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            ReferenceCount = Xml.GetChildUIntAttribute(node, "ReferenceCount", "value");
            FadeTime = Xml.GetChildFloatAttribute(node, "FadeTime", "value");
            Map = XmlRel.GetHash(Xml.GetChildInnerText(node, "Map"));
        }
        public override MetaHash[] GetMixerHashes()
        {
            return new[] { Map };
        }
    }
    [TC(typeof(EXP))] public class Dat15GroupList : Dat15RelData
    {
        public byte GroupCount { get; set; }
        public MetaHash[] Groups { get; set; }

        public Dat15GroupList(RelFile rel) : base(rel)
        {
            Type = Dat15RelType.GroupList;
            TypeID = (byte)Type;
        }
        public Dat15GroupList(RelData d, BinaryReader br) : base(d, br)
        {
            GroupCount = br.ReadByte();
            Groups = new MetaHash[GroupCount];
            for (int i = 0; i < GroupCount; i++)
            {
                Groups[i] = br.ReadUInt32();
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(GroupCount);
            for (int i = 0; i < GroupCount; i++)
            {
                bw.Write(Groups[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.WriteHashItemArray(sb, Groups, indent, "Groups");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Groups = XmlRel.ReadHashItemArray(node, "Groups");
            GroupCount = (byte)(Groups?.Length ?? 0);
        }
        public override MetaHash[] GetMixerHashes()
        {
            return Groups;
        }
    }
    [TC(typeof(EXP))] public class Dat15Unk5 : Dat15RelData
    {
        public MetaHash Unk01 { get; set; }//0
        public MetaHash ApplyVariable { get; set; }
        public MetaHash Unk03 { get; set; }//0
        public MetaHash Unk04 { get; set; }//Unk7 or Unk8 item

        public Dat15Unk5(RelFile rel) : base(rel)
        {
            Type = Dat15RelType.Unk5;
            TypeID = (byte)Type;
        }
        public Dat15Unk5(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();//0
            ApplyVariable = br.ReadUInt32();
            Unk03 = br.ReadUInt32();//0
            Unk04 = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(Unk01);
            bw.Write(ApplyVariable);
            bw.Write(Unk03);
            bw.Write(Unk04);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "ApplyVariable", RelXml.HashString(ApplyVariable));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
            RelXml.StringTag(sb, indent, "Unk04", RelXml.HashString(Unk04));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            ApplyVariable = XmlRel.GetHash(Xml.GetChildInnerText(node, "ApplyVariable"));
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
            Unk04 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk04"));
        }
        public override MetaHash[] GetMixerHashes()
        {
            return new[] { Unk04 };
        }
    }
    [TC(typeof(EXP))] public class Dat15Unk6 : Dat15RelData
    {
        public MetaHash Unk01 { get; set; }//what is this?
        public MetaHash Unk02 { get; set; }
        public byte ItemCount { get; set; }
        public float[] Items { get; set; }

        public Dat15Unk6(RelFile rel) : base(rel)
        {
            Type = Dat15RelType.Unk6;
            TypeID = (byte)Type;
        }
        public Dat15Unk6(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadUInt32();
            Unk02 = br.ReadUInt32();
            ItemCount = br.ReadByte();
            Items = new float[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = br.ReadSingle();
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                bw.Write(Items[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.StringTag(sb, indent, "Unk01", RelXml.HashString(Unk01));
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
            RelXml.WriteRawArray(sb, Items, indent, "Items", "", FloatUtil.ToString, 1);
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk01"));
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
            Items = Xml.GetChildRawFloatArray(node, "Items");
            ItemCount = (byte)(Items?.Length ?? 0);
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { Unk02 };
        }
    }
    [TC(typeof(EXP))] public class Dat15Unk7 : Dat15RelData
    {
        public byte Unk01 { get; set; }//could be an array count?
        public float Unk02 { get; set; }
        public MetaHash Unk03 { get; set; }//what is this?

        public Dat15Unk7(RelFile rel) : base(rel)
        {
            Type = Dat15RelType.Unk7;
            TypeID = (byte)Type;
        }
        public Dat15Unk7(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadByte();
            Unk02 = br.ReadSingle();
            Unk03 = br.ReadUInt32();

            //byte ItemCount = br.ReadByte();
            //var Items = new MetaHash[ItemCount];
            //for (int i = 0; i < ItemCount; i++)
            //{
            //    Items[i] = br.ReadUInt32();
            //}
            //if (ItemCount != 2)
            //{ }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
            bw.Write(Unk03);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Unk02", FloatUtil.ToString(Unk02));
            RelXml.StringTag(sb, indent, "Unk03", RelXml.HashString(Unk03));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = (byte)Xml.GetChildUIntAttribute(node, "Unk01", "value");
            Unk02 = Xml.GetChildFloatAttribute(node, "Unk02", "value");
            Unk03 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk03"));
        }
    }
    [TC(typeof(EXP))] public class Dat15Unk8 : Dat15RelData
    {
        public byte Unk01 { get; set; }
        public MetaHash Unk02 { get; set; }

        public Dat15Unk8(RelFile rel) : base(rel)
        {
            Type = Dat15RelType.Unk8;
            TypeID = (byte)Type;
        }
        public Dat15Unk8(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadByte();
            Unk02 = br.ReadUInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(Unk01);
            bw.Write(Unk02);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.StringTag(sb, indent, "Unk02", RelXml.HashString(Unk02));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = (byte)Xml.GetChildUIntAttribute(node, "Unk01", "value");
            Unk02 = XmlRel.GetHash(Xml.GetChildInnerText(node, "Unk02"));
        }
        public override MetaHash[] GetSoundHashes()
        {
            return new[] { Unk02 };
        }
    }
    [TC(typeof(EXP))] public class Dat15GroupMap : Dat15RelData
    {
        public ushort ItemCount { get; set; }
        public Dat151HashPair[] Items { get; set; }

        public Dat15GroupMap(RelFile rel) : base(rel)
        {
            Type = Dat15RelType.GroupMap;
            TypeID = (byte)Type;
        }
        public Dat15GroupMap(RelData d, BinaryReader br) : base(d, br)
        {
            ItemCount = br.ReadUInt16();
            Items = new Dat151HashPair[ItemCount];
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i] = new Dat151HashPair(br);
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(ItemCount);
            for (int i = 0; i < ItemCount; i++)
            {
                Items[i].Write(bw);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.WriteItemArray(sb, Items, indent, "Items");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Items = XmlRel.ReadItemArray<Dat151HashPair>(node, "Items");
            ItemCount = (ushort)(Items?.Length ?? 0);
        }
        public override MetaHash[] GetCategoryHashes()
        {
            var list = new List<MetaHash>();
            if (Items != null)
            {
                foreach (var item in Items)
                {
                    list.Add(item.Hash0);
                    list.Add(item.Hash1);
                }
            }
            return list.ToArray();
        }
    }



    #endregion




    #region dat16


    public enum Dat16RelType : byte
    {
        //BaseCurve = 0,
        ConstantCurve = 1,
        LinearCurve = 2,
        LinearDbCurve = 3,
        PiecewiseLinearCurve = 4,
        EqualPowerCurve = 5,
        ValueTableCurve = 6,
        ExponentialCurve = 7,
        DecayingExponentialCurve = 8,
        DecayingSquaredExponentialCurve = 9,
        SineCurve = 10,
        //OneOverXCurve = 11,
        OneOverXSquaredCurve = 12,
        DefaultDistanceAttenuationCurve = 13,
        //DefaultDistanceAttenuationClampedCurve = 14,
        DistanceAttenuationValueTableCurve = 15,
        //CurveSet = 16,
        //BezierCurve = 17,
    }

    [TC(typeof(EXP))] public class Dat16RelData : RelData
    {
        public Dat16RelType Type { get; set; }
        public uint NameTableOffset { get; set; }
        public FlagsUint Flags { get; set; }

        public Dat16RelData(RelFile rel) : base(rel) { }
        public Dat16RelData(RelFile rel, Dat16RelType type) : base(rel)
        {
            Type = type;
            TypeID = (byte)type;
        }
        public Dat16RelData(RelData d, BinaryReader br) : base(d)
        {
            Type = (Dat16RelType)TypeID;

            br.BaseStream.Position = 0; //1 byte was read already (TypeID)

            NameTableOffset = ((br.ReadUInt32() >> 8) & 0xFFFFFF);
            Flags = br.ReadUInt32();
        }

        public void WriteTypeAndOffsetAndFlags(BinaryWriter bw)
        {
            var val = ((NameTableOffset & 0xFFFFFF) << 8) + TypeID;
            bw.Write(val);
            bw.Write(Flags);
        }

        public override string ToString()
        {
            return GetBaseString() + ": " + Type.ToString();
        }
    }

    [TC(typeof(EXP))] public class Dat16ConstantCurve : Dat16RelData
    {
        public float MinInput { get; set; }
        public float MaxInput { get; set; }
        public float Value { get; set; }

        public Dat16ConstantCurve(RelFile rel) : base(rel)
        {
            Type = Dat16RelType.ConstantCurve;
            TypeID = (byte)Type;
        }
        public Dat16ConstantCurve(RelData d, BinaryReader br) : base(d, br)
        {
            MinInput = br.ReadSingle();
            MaxInput = br.ReadSingle();
            Value = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(MinInput);
            bw.Write(MaxInput);
            bw.Write(Value);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "MinInput", FloatUtil.ToString(MinInput));
            RelXml.ValueTag(sb, indent, "MaxInput", FloatUtil.ToString(MaxInput));
            RelXml.ValueTag(sb, indent, "Value", FloatUtil.ToString(Value));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            MinInput = Xml.GetChildFloatAttribute(node, "MinInput", "value");
            MaxInput = Xml.GetChildFloatAttribute(node, "MaxInput", "value");
            Value = Xml.GetChildFloatAttribute(node, "Value", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat16LinearCurve : Dat16RelData
    {
        public float MinInput { get; set; }
        public float MaxInput { get; set; }
        public float Unk03 { get; set; }
        public float Unk04 { get; set; }
        public float Unk05 { get; set; }
        public float Unk06 { get; set; }

        public Dat16LinearCurve(RelFile rel) : base(rel)
        {
            Type = Dat16RelType.LinearCurve;
            TypeID = (byte)Type;
        }
        public Dat16LinearCurve(RelData d, BinaryReader br) : base(d, br)
        {
            MinInput = br.ReadSingle();
            MaxInput = br.ReadSingle();
            Unk03 = br.ReadSingle();
            Unk04 = br.ReadSingle();
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(MinInput);
            bw.Write(MaxInput);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "MinInput", FloatUtil.ToString(MinInput));
            RelXml.ValueTag(sb, indent, "MaxInput", FloatUtil.ToString(MaxInput));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            MinInput = Xml.GetChildFloatAttribute(node, "MinInput", "value");
            MaxInput = Xml.GetChildFloatAttribute(node, "MaxInput", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat16LinearDbCurve : Dat16RelData
    {
        public float MinInput { get; set; }
        public float MaxInput { get; set; }
        public float Unk03 { get; set; }//0 (probably float)
        public float Unk04 { get; set; }//0 (probably float)
        public float Unk05 { get; set; }
        public float Unk06 { get; set; }

        public Dat16LinearDbCurve(RelFile rel) : base(rel)
        {
            Type = Dat16RelType.LinearDbCurve;
            TypeID = (byte)Type;
        }
        public Dat16LinearDbCurve(RelData d, BinaryReader br) : base(d, br)
        {
            MinInput = br.ReadSingle();
            MaxInput = br.ReadSingle();
            Unk03 = br.ReadSingle();//0
            Unk04 = br.ReadSingle();//0
            Unk05 = br.ReadSingle();
            Unk06 = br.ReadSingle();

            if (Unk03 != 0)
            { }
            if (Unk04 != 0)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(MinInput);
            bw.Write(MaxInput);
            bw.Write(Unk03);
            bw.Write(Unk04);
            bw.Write(Unk05);
            bw.Write(Unk06);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "MinInput", FloatUtil.ToString(MinInput));
            RelXml.ValueTag(sb, indent, "MaxInput", FloatUtil.ToString(MaxInput));
            RelXml.ValueTag(sb, indent, "Unk03", FloatUtil.ToString(Unk03));
            RelXml.ValueTag(sb, indent, "Unk04", FloatUtil.ToString(Unk04));
            RelXml.ValueTag(sb, indent, "Unk05", FloatUtil.ToString(Unk05));
            RelXml.ValueTag(sb, indent, "Unk06", FloatUtil.ToString(Unk06));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            MinInput = Xml.GetChildFloatAttribute(node, "MinInput", "value");
            MaxInput = Xml.GetChildFloatAttribute(node, "MaxInput", "value");
            Unk03 = Xml.GetChildFloatAttribute(node, "Unk03", "value");
            Unk04 = Xml.GetChildFloatAttribute(node, "Unk04", "value");
            Unk05 = Xml.GetChildFloatAttribute(node, "Unk05", "value");
            Unk06 = Xml.GetChildFloatAttribute(node, "Unk06", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat16PiecewiseLinearCurve : Dat16RelData
    {
        public float MinInput { get; set; }
        public float MaxInput { get; set; }
        public int PointCount { get; set; }
        public Vector2[] Points { get; set; }

        public Dat16PiecewiseLinearCurve(RelFile rel) : base(rel)
        {
            Type = Dat16RelType.PiecewiseLinearCurve;
            TypeID = (byte)Type;
        }
        public Dat16PiecewiseLinearCurve(RelData d, BinaryReader br) : base(d, br)
        {
            MinInput = br.ReadSingle();
            MaxInput = br.ReadSingle();
            PointCount = br.ReadInt32();
            Points = new Vector2[PointCount];
            for (int i = 0; i < PointCount; i++)
            {
                Points[i] = new Vector2(br.ReadSingle(), br.ReadSingle());
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(MinInput);
            bw.Write(MaxInput);
            bw.Write(PointCount);
            for (int i = 0; i < PointCount; i++)
            {
                bw.Write(Points[i].X);
                bw.Write(Points[i].Y);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "MinInput", FloatUtil.ToString(MinInput));
            RelXml.ValueTag(sb, indent, "MaxInput", FloatUtil.ToString(MaxInput));
            RelXml.WriteRawArray(sb, Points, indent, "Points", "", RelXml.FormatVector2, 1);
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            MinInput = Xml.GetChildFloatAttribute(node, "MinInput", "value");
            MaxInput = Xml.GetChildFloatAttribute(node, "MaxInput", "value");
            Points = Xml.GetChildRawVector2Array(node, "Points");
            PointCount = Points?.Length ?? 0;
        }
    }
    [TC(typeof(EXP))] public class Dat16EqualPowerCurve : Dat16RelData
    {
        public float MinInput { get; set; }
        public float MaxInput { get; set; }
        public int Flip { get; set; }

        public Dat16EqualPowerCurve(RelFile rel) : base(rel)
        {
            Type = Dat16RelType.EqualPowerCurve;
            TypeID = (byte)Type;
        }
        public Dat16EqualPowerCurve(RelData d, BinaryReader br) : base(d, br)
        {
            MinInput = br.ReadSingle();
            MaxInput = br.ReadSingle();
            Flip = br.ReadInt32();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(MinInput);
            bw.Write(MaxInput);
            bw.Write(Flip);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "MinInput", FloatUtil.ToString(MinInput));
            RelXml.ValueTag(sb, indent, "MaxInput", FloatUtil.ToString(MaxInput));
            RelXml.ValueTag(sb, indent, "Flip", Flip.ToString());
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            MinInput = Xml.GetChildFloatAttribute(node, "MinInput", "value");
            MaxInput = Xml.GetChildFloatAttribute(node, "MaxInput", "value");
            Flip = Xml.GetChildIntAttribute(node, "Flip", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat16ValueTableCurve : Dat16RelData
    {
        public float MinInput { get; set; }
        public float MaxInput { get; set; }
        public int ValueCount { get; set; }
        public float[] Values { get; set; }

        public Dat16ValueTableCurve(RelFile rel) : base(rel)
        {
            Type = Dat16RelType.ValueTableCurve;
            TypeID = (byte)Type;
        }
        public Dat16ValueTableCurve(RelData d, BinaryReader br) : base(d, br)
        {
            MinInput = br.ReadSingle();
            MaxInput = br.ReadSingle();
            ValueCount = br.ReadInt32();
            Values = new float[ValueCount];
            for (int i = 0; i < ValueCount; i++)
            {
                Values[i] = br.ReadSingle();
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(MinInput);
            bw.Write(MaxInput);
            bw.Write(ValueCount);
            for (int i = 0; i < ValueCount; i++)
            {
                bw.Write(Values[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "MinInput", FloatUtil.ToString(MinInput));
            RelXml.ValueTag(sb, indent, "MaxInput", FloatUtil.ToString(MaxInput));
            RelXml.WriteRawArray(sb, Values, indent, "Values", "", FloatUtil.ToString, 1);
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            MinInput = Xml.GetChildFloatAttribute(node, "MinInput", "value");
            MaxInput = Xml.GetChildFloatAttribute(node, "MaxInput", "value");
            Values = Xml.GetChildRawFloatArray(node, "Values");
            ValueCount = (Values?.Length ?? 0);
        }
    }
    [TC(typeof(EXP))] public class Dat16ExponentialCurve : Dat16RelData
    {
        public float MinInput { get; set; }
        public float MaxInput { get; set; }
        public int Flip { get; set; }
        public float Exponent { get; set; }

        public Dat16ExponentialCurve(RelFile rel) : base(rel)
        {
            Type = Dat16RelType.ExponentialCurve;
            TypeID = (byte)Type;
        }
        public Dat16ExponentialCurve(RelData d, BinaryReader br) : base(d, br)
        {
            MinInput = br.ReadSingle();
            MaxInput = br.ReadSingle();
            Flip = br.ReadInt32();
            Exponent = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(MinInput);
            bw.Write(MaxInput);
            bw.Write(Flip);
            bw.Write(Exponent);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "MinInput", FloatUtil.ToString(MinInput));
            RelXml.ValueTag(sb, indent, "MaxInput", FloatUtil.ToString(MaxInput));
            RelXml.ValueTag(sb, indent, "Flip", Flip.ToString());
            RelXml.ValueTag(sb, indent, "Exponent", FloatUtil.ToString(Exponent));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            MinInput = Xml.GetChildFloatAttribute(node, "MinInput", "value");
            MaxInput = Xml.GetChildFloatAttribute(node, "MaxInput", "value");
            Flip = Xml.GetChildIntAttribute(node, "Flip", "value");
            Exponent = Xml.GetChildFloatAttribute(node, "Exponent", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat16DecayingExponentialCurve : Dat16RelData
    {
        public float MinInput { get; set; }
        public float MaxInput { get; set; }
        public float HorizontalScaling { get; set; }

        public Dat16DecayingExponentialCurve(RelFile rel) : base(rel)
        {
            Type = Dat16RelType.DecayingExponentialCurve;
            TypeID = (byte)Type;
        }
        public Dat16DecayingExponentialCurve(RelData d, BinaryReader br) : base(d, br)
        {
            MinInput = br.ReadSingle();
            MaxInput = br.ReadSingle();
            HorizontalScaling = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(MinInput);
            bw.Write(MaxInput);
            bw.Write(HorizontalScaling);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "MinInput", FloatUtil.ToString(MinInput));
            RelXml.ValueTag(sb, indent, "MaxInput", FloatUtil.ToString(MaxInput));
            RelXml.ValueTag(sb, indent, "HorizontalScaling", FloatUtil.ToString(HorizontalScaling));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            MinInput = Xml.GetChildFloatAttribute(node, "MinInput", "value");
            MaxInput = Xml.GetChildFloatAttribute(node, "MaxInput", "value");
            HorizontalScaling = Xml.GetChildFloatAttribute(node, "HorizontalScaling", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat16DecayingSquaredExponentialCurve : Dat16RelData
    {
        public float MinInput { get; set; }
        public float MaxInput { get; set; }
        public float HorizontalScaling { get; set; }

        public Dat16DecayingSquaredExponentialCurve(RelFile rel) : base(rel)
        {
            Type = Dat16RelType.DecayingSquaredExponentialCurve;
            TypeID = (byte)Type;
        }
        public Dat16DecayingSquaredExponentialCurve(RelData d, BinaryReader br) : base(d, br)
        {
            MinInput = br.ReadSingle();
            MaxInput = br.ReadSingle();
            HorizontalScaling = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(MinInput);
            bw.Write(MaxInput);
            bw.Write(HorizontalScaling);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "MinInput", FloatUtil.ToString(MinInput));
            RelXml.ValueTag(sb, indent, "MaxInput", FloatUtil.ToString(MaxInput));
            RelXml.ValueTag(sb, indent, "HorizontalScaling", FloatUtil.ToString(HorizontalScaling));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            MinInput = Xml.GetChildFloatAttribute(node, "MinInput", "value");
            MaxInput = Xml.GetChildFloatAttribute(node, "MaxInput", "value");
            HorizontalScaling = Xml.GetChildFloatAttribute(node, "HorizontalScaling", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat16SineCurve : Dat16RelData
    {
        public float MinInput { get; set; }
        public float MaxInput { get; set; }
        public float StartPhase { get; set; }
        public float EndPhase { get; set; }
        public float Frequency { get; set; }
        public float VerticalScaling { get; set; }
        public float VerticalOffset { get; set; }

        public Dat16SineCurve(RelFile rel) : base(rel)
        {
            Type = Dat16RelType.SineCurve;
            TypeID = (byte)Type;
        }
        public Dat16SineCurve(RelData d, BinaryReader br) : base(d, br)
        {
            MinInput = br.ReadSingle();
            MaxInput = br.ReadSingle();
            StartPhase = br.ReadSingle();
            EndPhase = br.ReadSingle();
            Frequency = br.ReadSingle();
            VerticalScaling = br.ReadSingle();
            VerticalOffset = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(MinInput);
            bw.Write(MaxInput);
            bw.Write(StartPhase);
            bw.Write(EndPhase);
            bw.Write(Frequency);
            bw.Write(VerticalScaling);
            bw.Write(VerticalOffset);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "MinInput", FloatUtil.ToString(MinInput));
            RelXml.ValueTag(sb, indent, "MaxInput", FloatUtil.ToString(MaxInput));
            RelXml.ValueTag(sb, indent, "StartPhase", FloatUtil.ToString(StartPhase));
            RelXml.ValueTag(sb, indent, "EndPhase", FloatUtil.ToString(EndPhase));
            RelXml.ValueTag(sb, indent, "Frequency", FloatUtil.ToString(Frequency));
            RelXml.ValueTag(sb, indent, "VerticalScaling", FloatUtil.ToString(VerticalScaling));
            RelXml.ValueTag(sb, indent, "VerticalOffset", FloatUtil.ToString(VerticalOffset));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            MinInput = Xml.GetChildFloatAttribute(node, "MinInput", "value");
            MaxInput = Xml.GetChildFloatAttribute(node, "MaxInput", "value");
            StartPhase = Xml.GetChildFloatAttribute(node, "StartPhase", "value");
            EndPhase = Xml.GetChildFloatAttribute(node, "EndPhase", "value");
            Frequency = Xml.GetChildFloatAttribute(node, "Frequency", "value");
            VerticalScaling = Xml.GetChildFloatAttribute(node, "VerticalScaling", "value");
            VerticalOffset = Xml.GetChildFloatAttribute(node, "VerticalOffset", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat16OneOverXSquaredCurve : Dat16RelData
    {
        public float MinInput { get; set; }
        public float MaxInput { get; set; }
        public float HorizontalScaling { get; set; }

        public Dat16OneOverXSquaredCurve(RelFile rel) : base(rel)
        {
            Type = Dat16RelType.OneOverXSquaredCurve;
            TypeID = (byte)Type;
        }
        public Dat16OneOverXSquaredCurve(RelData d, BinaryReader br) : base(d, br)
        {
            MinInput = br.ReadSingle();
            MaxInput = br.ReadSingle();
            HorizontalScaling = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(MinInput);
            bw.Write(MaxInput);
            bw.Write(HorizontalScaling);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "MinInput", FloatUtil.ToString(MinInput));
            RelXml.ValueTag(sb, indent, "MaxInput", FloatUtil.ToString(MaxInput));
            RelXml.ValueTag(sb, indent, "HorizontalScaling", FloatUtil.ToString(HorizontalScaling));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            MinInput = Xml.GetChildFloatAttribute(node, "MinInput", "value");
            MaxInput = Xml.GetChildFloatAttribute(node, "MaxInput", "value");
            HorizontalScaling = Xml.GetChildFloatAttribute(node, "HorizontalScaling", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat16DefaultDistanceAttenuationCurve : Dat16RelData
    {
        public float MinInput { get; set; }
        public float MaxInput { get; set; }

        public Dat16DefaultDistanceAttenuationCurve(RelFile rel) : base(rel)
        {
            Type = Dat16RelType.DefaultDistanceAttenuationCurve;
            TypeID = (byte)Type;
        }
        public Dat16DefaultDistanceAttenuationCurve(RelData d, BinaryReader br) : base(d, br)
        {
            MinInput = br.ReadSingle();
            MaxInput = br.ReadSingle();

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(MinInput);
            bw.Write(MaxInput);
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "MinInput", FloatUtil.ToString(MinInput));
            RelXml.ValueTag(sb, indent, "MaxInput", FloatUtil.ToString(MaxInput));
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            MinInput = Xml.GetChildFloatAttribute(node, "MinInput", "value");
            MaxInput = Xml.GetChildFloatAttribute(node, "MaxInput", "value");
        }
    }
    [TC(typeof(EXP))] public class Dat16DistanceAttenuationValueTableCurve : Dat16RelData
    {
        public float MinInput { get; set; }
        public float MaxInput { get; set; }
        public int ValueCount { get; set; }
        public float[] Values { get; set; }

        public Dat16DistanceAttenuationValueTableCurve(RelFile rel) : base(rel)
        {
            Type = Dat16RelType.DistanceAttenuationValueTableCurve;
            TypeID = (byte)Type;
        }
        public Dat16DistanceAttenuationValueTableCurve(RelData d, BinaryReader br) : base(d, br)
        {
            MinInput = br.ReadSingle();
            MaxInput = br.ReadSingle();
            ValueCount = br.ReadInt32();
            Values = new float[ValueCount];
            for (int i = 0; i < ValueCount; i++)
            {
                Values[i] = br.ReadSingle();
            }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(MinInput);
            bw.Write(MaxInput);
            bw.Write(ValueCount);
            for (int i = 0; i < ValueCount; i++)
            {
                bw.Write(Values[i]);
            }
        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "MinInput", FloatUtil.ToString(MinInput));
            RelXml.ValueTag(sb, indent, "MaxInput", FloatUtil.ToString(MaxInput));
            RelXml.WriteRawArray(sb, Values, indent, "Values", "", FloatUtil.ToString, 1);
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            MinInput = Xml.GetChildFloatAttribute(node, "MinInput", "value");
            MaxInput = Xml.GetChildFloatAttribute(node, "MaxInput", "value");
            Values = Xml.GetChildRawFloatArray(node, "Values");
            ValueCount = (Values?.Length ?? 0);
        }
    }


    #endregion




    #region dat22


    public enum Dat22RelType : byte
    {
        Category = 0,
    }

    [TC(typeof(EXP))] public class Dat22RelData : RelData
    {
        public Dat22RelType Type { get; set; }
        public uint NameTableOffset { get; set; }
        public FlagsUint Flags { get; set; }

        public Dat22RelData(RelFile rel) : base(rel) { }
        public Dat22RelData(RelFile rel, Dat22RelType type) : base(rel)
        {
            Type = type;
            TypeID = (byte)type;
        }
        public Dat22RelData(RelData d, BinaryReader br) : base(d)
        {
            Type = (Dat22RelType)TypeID;

            br.BaseStream.Position = 0; //1 byte was read already (TypeID)

            NameTableOffset = ((br.ReadUInt32() >> 8) & 0xFFFFFF);
            Flags = br.ReadUInt32();
        }

        public void WriteTypeAndOffsetAndFlags(BinaryWriter bw)
        {
            var val = ((NameTableOffset & 0xFFFFFF) << 8) + TypeID;
            bw.Write(val);
            bw.Write(Flags);
        }

        public override string ToString()
        {
            return GetBaseString() + ": " + Type.ToString();
        }
    }

    [TC(typeof(EXP))] public class Dat22Category : Dat22RelData
    {
        public short Unk01 { get; set; }
        public short Volume { get; set; }
        public short Unk03 { get; set; }
        public short LPFCutoff { get; set; }
        public MetaHash LPFCutoffCurve { get; set; }//1757063444
        public short HPFCutoff { get; set; }
        public MetaHash HPFCutoffCurve { get; set; }//741353067
        public short Unk08 { get; set; }
        public short Unk09 { get; set; }
        public short Unk10 { get; set; }
        public short Unk11 { get; set; }
        public short Unk12 { get; set; }
        public short Unk13 { get; set; }
        public short Unk14 { get; set; }
        public short Unk15 { get; set; }
        public short Unk16 { get; set; }
        public short Unk17 { get; set; }
        public byte Unk18 { get; set; }
        public byte SubCategoryCount { get; set; }
        public MetaHash[] SubCategories { get; set; }

        public Dat22Category(RelFile rel) : base(rel)
        {
            Type = Dat22RelType.Category;
            TypeID = (byte)Type;
        }
        public Dat22Category(RelData d, BinaryReader br) : base(d, br)
        {
            Unk01 = br.ReadInt16();
            Volume = br.ReadInt16();
            Unk03 = br.ReadInt16();
            LPFCutoff = br.ReadInt16();
            LPFCutoffCurve = br.ReadUInt32();//1757063444
            HPFCutoff = br.ReadInt16();
            HPFCutoffCurve = br.ReadUInt32();//741353067
            Unk08 = br.ReadInt16();
            Unk09 = br.ReadInt16();
            Unk10 = br.ReadInt16();
            Unk11 = br.ReadInt16();
            Unk12 = br.ReadInt16();
            Unk13 = br.ReadInt16();
            Unk14 = br.ReadInt16();
            Unk15 = br.ReadInt16();
            Unk16 = br.ReadInt16();
            Unk17 = br.ReadInt16();
            Unk18 = br.ReadByte();
            SubCategoryCount = br.ReadByte();
            SubCategories = new MetaHash[SubCategoryCount];
            for (int i = 0; i < SubCategoryCount; i++)
            {
                SubCategories[i] = br.ReadUInt32();
            }

            if (LPFCutoffCurve != 1757063444)
            { }
            if (HPFCutoffCurve != 741353067)
            { }

            var bytesleft = br.BaseStream.Length - br.BaseStream.Position;
            if (bytesleft != 0)
            { }
        }
        public override void Write(BinaryWriter bw)
        {
            WriteTypeAndOffsetAndFlags(bw);

            bw.Write(Unk01);
            bw.Write(Volume);
            bw.Write(Unk03);
            bw.Write(LPFCutoff);
            bw.Write(LPFCutoffCurve);
            bw.Write(HPFCutoff);
            bw.Write(HPFCutoffCurve);
            bw.Write(Unk08);
            bw.Write(Unk09);
            bw.Write(Unk10);
            bw.Write(Unk11);
            bw.Write(Unk12);
            bw.Write(Unk13);
            bw.Write(Unk14);
            bw.Write(Unk15);
            bw.Write(Unk16);
            bw.Write(Unk17);
            bw.Write(Unk18);
            bw.Write(SubCategoryCount);
            for (int i = 0; i < SubCategoryCount; i++)
            {
                bw.Write(SubCategories[i]);
            }

        }
        public override void WriteXml(StringBuilder sb, int indent)
        {
            RelXml.ValueTag(sb, indent, "Flags", "0x" + Flags.Hex);
            RelXml.ValueTag(sb, indent, "Unk01", Unk01.ToString());
            RelXml.ValueTag(sb, indent, "Volume", Volume.ToString());
            RelXml.ValueTag(sb, indent, "Unk03", Unk03.ToString());
            RelXml.ValueTag(sb, indent, "LPFCutoff", LPFCutoff.ToString());
            RelXml.StringTag(sb, indent, "LPFCutoffCurve", RelXml.HashString(LPFCutoffCurve));
            RelXml.ValueTag(sb, indent, "HPFCutoff", HPFCutoff.ToString());
            RelXml.StringTag(sb, indent, "HPFCutoffCurve", RelXml.HashString(HPFCutoffCurve));
            RelXml.ValueTag(sb, indent, "Unk08", Unk08.ToString());
            RelXml.ValueTag(sb, indent, "Unk09", Unk09.ToString());
            RelXml.ValueTag(sb, indent, "Unk10", Unk10.ToString());
            RelXml.ValueTag(sb, indent, "Unk11", Unk11.ToString());
            RelXml.ValueTag(sb, indent, "Unk12", Unk12.ToString());
            RelXml.ValueTag(sb, indent, "Unk13", Unk13.ToString());
            RelXml.ValueTag(sb, indent, "Unk14", Unk14.ToString());
            RelXml.ValueTag(sb, indent, "Unk15", Unk15.ToString());
            RelXml.ValueTag(sb, indent, "Unk16", Unk16.ToString());
            RelXml.ValueTag(sb, indent, "Unk17", Unk17.ToString());
            RelXml.ValueTag(sb, indent, "Unk18", Unk18.ToString());
            RelXml.WriteHashItemArray(sb, SubCategories, indent, "SubCategories");
        }
        public override void ReadXml(XmlNode node)
        {
            Flags = Xml.GetChildUIntAttribute(node, "Flags", "value");
            Unk01 = (short)Xml.GetChildIntAttribute(node, "Unk01", "value");
            Volume = (short)Xml.GetChildIntAttribute(node, "Volume", "value");
            Unk03 = (short)Xml.GetChildIntAttribute(node, "Unk03", "value");
            LPFCutoff = (short)Xml.GetChildIntAttribute(node, "LPFCutoff", "value");
            LPFCutoffCurve = XmlRel.GetHash(Xml.GetChildInnerText(node, "LPFCutoffCurve"));
            HPFCutoff = (short)Xml.GetChildIntAttribute(node, "HPFCutoff", "value");
            HPFCutoffCurve = XmlRel.GetHash(Xml.GetChildInnerText(node, "HPFCutoffCurve"));
            Unk08 = (short)Xml.GetChildIntAttribute(node, "Unk08", "value");
            Unk09 = (short)Xml.GetChildIntAttribute(node, "Unk09", "value");
            Unk10 = (short)Xml.GetChildIntAttribute(node, "Unk10", "value");
            Unk11 = (short)Xml.GetChildIntAttribute(node, "Unk11", "value");
            Unk12 = (short)Xml.GetChildIntAttribute(node, "Unk12", "value");
            Unk13 = (short)Xml.GetChildIntAttribute(node, "Unk13", "value");
            Unk14 = (short)Xml.GetChildIntAttribute(node, "Unk14", "value");
            Unk15 = (short)Xml.GetChildIntAttribute(node, "Unk15", "value");
            Unk16 = (short)Xml.GetChildIntAttribute(node, "Unk16", "value");
            Unk17 = (short)Xml.GetChildIntAttribute(node, "Unk17", "value");
            Unk18 = (byte)Xml.GetChildUIntAttribute(node, "Unk18", "value");
            SubCategories = XmlRel.ReadHashItemArray(node, "SubCategories");
            SubCategoryCount = (byte)(SubCategories?.Length ?? 0);
        }
        public override MetaHash[] GetCurveHashes()
        {
            return new[] { LPFCutoffCurve, HPFCutoffCurve };
        }
        public override MetaHash[] GetCategoryHashes()
        {
            return SubCategories;
        }
    }


    #endregion













    public class RelXml : MetaXmlBase
    {

        public static string GetXml(RelFile rel)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(XmlHeader);

            if ((rel != null) && (rel.RelDatasSorted != null))
            {
                int indent = 0;
                int cindent = 1;
                var iindent = 2;
                var name = "Dat" + ((uint)rel.RelType).ToString();

                OpenTag(sb, indent, name);

                ValueTag(sb, cindent, "Version", rel.DataUnkVal.ToString());

                if (rel.IsAudioConfig)
                {
                    ValueTag(sb, cindent, "IsAudioConfig", "true");
                }

                if (rel.NameTable != null)
                {
                    OpenTag(sb, cindent, "ContainerPaths");

                    foreach (var ntval in rel.NameTable)
                    {
                        StringTag(sb, iindent, "Item", ntval);
                    }

                    CloseTag(sb, cindent, "ContainerPaths");
                }

                OpenTag(sb, cindent, "Items");

                foreach (var item in rel.RelDatasSorted)
                {
                    GetXml(item, sb, iindent);
                }

                CloseTag(sb, cindent, "Items");

                CloseTag(sb, indent, name);

            }

            return sb.ToString();
        }

        public static void GetXml(RelData item, StringBuilder sb, int iindent)
        {
            var icindent = iindent + 1;
            var rel = item.Rel;
            var typeid = item.TypeID.ToString();
            switch (rel.RelType)
            {
                case RelDatFileType.Dat54DataEntries:
                    typeid = ((Dat54SoundType)item.TypeID).ToString();
                    break;
                case RelDatFileType.Dat149:
                case RelDatFileType.Dat150:
                case RelDatFileType.Dat151:
                    typeid = ((Dat151RelType)item.TypeID).ToString();
                    break;
                case RelDatFileType.Dat4:
                    if (rel.IsAudioConfig) typeid = ((Dat4ConfigType)item.TypeID).ToString();
                    else typeid = ((Dat4SpeechType)item.TypeID).ToString();
                    break;
                case RelDatFileType.Dat10ModularSynth:
                    typeid = ((Dat10RelType)item.TypeID).ToString();
                    break;
                case RelDatFileType.Dat15DynamicMixer:
                    typeid = ((Dat15RelType)item.TypeID).ToString();
                    break;
                case RelDatFileType.Dat16Curves:
                    typeid = ((Dat16RelType)item.TypeID).ToString();
                    break;
                case RelDatFileType.Dat22Categories:
                    typeid = ((Dat22RelType)item.TypeID).ToString();
                    break;
                default:
                    break;
            }

            var ntoffset = "";
            var dat151item = item as Dat151RelData;
            if (dat151item != null)
            {
                ntoffset = " ntOffset=\"" + dat151item.NameTableOffset.ToString() + "\"";
            }
            var dat4config = item as Dat4ConfigData;
            if (dat4config != null)
            {
                ntoffset = " ntOffset=\"" + dat4config.NameTableOffset.ToString() + "\"";
            }
            var dat4Speech = item as Dat4SpeechData;
            if (dat4Speech != null)
            {
                if (dat4Speech.Type == Dat4SpeechType.Container)
                {
                    ntoffset = " ntOffset=\"" + dat4Speech.NameTableOffset.ToString() + "\"";
                }
            }
            var dat10item = item as Dat10RelData;
            if (dat10item != null)
            {
                ntoffset = " ntOffset=\"" + dat10item.NameTableOffset.ToString() + "\"";
            }
            var dat15item = item as Dat15RelData;
            if (dat15item != null)
            {
                ntoffset = " ntOffset=\"" + dat15item.NameTableOffset.ToString() + "\"";
            }
            var dat16item = item as Dat16RelData;
            if (dat16item != null)
            {
                ntoffset = " ntOffset=\"" + dat16item.NameTableOffset.ToString() + "\"";
            }
            var dat22item = item as Dat22RelData;
            if (dat22item != null)
            {
                ntoffset = " ntOffset=\"" + dat22item.NameTableOffset.ToString() + "\"";
            }

            OpenTag(sb, iindent, "Item type=\"" + typeid + "\"" + ntoffset);

            StringTag(sb, icindent, "Name", item.Name ?? RelXml.HashString(item.NameHash));

            item.WriteXml(sb, icindent);

            CloseTag(sb, iindent, "Item");

        }
        public static string GetXml(RelData item, int indent = 0)
        {
            var sb = new StringBuilder();
            GetXml(item, sb, indent);
            return sb.ToString();
        }

    }

    public class XmlRel
    {

        public static RelFile GetRel(string xml)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);
            return GetRel(doc);
        }

        public static RelFile GetRel(XmlDocument doc)
        {

            var node = doc.DocumentElement;
            var reltypestr = node.Name.Substring(3);
            var reltypeint = uint.Parse(reltypestr);
            var reltype = (RelDatFileType)reltypeint;

            switch (reltype)
            {
                case RelDatFileType.Dat4://TODO!
                case RelDatFileType.Dat54DataEntries://TODO!
                    break;// return null; //TODO
            }

            RelFile rel = new RelFile();
            rel.RelType = reltype;
            rel.DataUnkVal = Xml.GetChildUIntAttribute(node, "Version", "value");
            rel.IsAudioConfig = Xml.GetChildBoolAttribute(node, "IsAudioConfig", "value");

            var ntnode = node.SelectSingleNode("ContainerPaths");
            if (ntnode != null)
            {
                var ntstrs = new List<string>();
                var ntitems = ntnode.SelectNodes("Item");
                foreach (XmlNode ntitem in ntitems)
                {
                    ntstrs.Add(ntitem.InnerText);
                }
                rel.NameTable = ntstrs.ToArray();
                rel.NameTableCount = (uint)ntstrs.Count;
            }

            var itemsnode = node.SelectSingleNode("Items");
            if (itemsnode != null)
            {
                var itemslist = new List<RelData>();
                var items = itemsnode.SelectNodes("Item");
                foreach (XmlNode item in items)
                {
                    var ntoffset = Xml.GetUIntAttribute(item, "ntOffset");
                    var typestr = Xml.GetStringAttribute(item, "type");
                    var typeid = -1;
                    switch (reltype)
                    {
                        case RelDatFileType.Dat54DataEntries:
                            Dat54SoundType st;
                            if (Enum.TryParse(typestr, out st))
                            {
                                typeid = (int)st;
                            }
                            break;
                        case RelDatFileType.Dat149:
                        case RelDatFileType.Dat150:
                        case RelDatFileType.Dat151:
                            Dat151RelType rt;
                            if (Enum.TryParse(typestr, out rt))
                            {
                                typeid = (int)rt;
                            }
                            break;
                        case RelDatFileType.Dat4:
                            if (rel.IsAudioConfig)
                            {
                                Dat4ConfigType ct;
                                if (Enum.TryParse(typestr, out ct))
                                {
                                    typeid = (int)ct;
                                }
                            }
                            else
                            {
                                Dat4SpeechType spt;
                                if (Enum.TryParse(typestr, out spt))
                                {
                                    typeid = (int)spt;
                                }
                            }
                            break;
                        case RelDatFileType.Dat10ModularSynth:
                            Dat10RelType mst;
                            if (Enum.TryParse(typestr, out mst))
                            {
                                typeid = (int)mst;
                            }
                            break;
                        case RelDatFileType.Dat15DynamicMixer:
                            Dat15RelType dmt;
                            if (Enum.TryParse(typestr, out dmt))
                            {
                                typeid = (int)dmt;
                            }
                            break;
                        case RelDatFileType.Dat16Curves:
                            Dat16RelType cvt;
                            if (Enum.TryParse(typestr, out cvt))
                            {
                                typeid = (int)cvt;
                            }
                            break;
                        case RelDatFileType.Dat22Categories:
                            Dat22RelType cat;
                            if (Enum.TryParse(typestr, out cat))
                            {
                                typeid = (int)cat;
                            }
                            break;
                    }
                    if (typeid < 0)
                    {
                        if (!int.TryParse(typestr, out typeid))
                        {
                            continue;//couldn't determine type!
                        }
                    }


                    RelData rd = rel.CreateRelData(reltype, typeid);
                    rd.Name = Xml.GetChildInnerText(item, "Name");
                    rd.NameHash = XmlRel.GetHash(rd.Name);
                    rd.ReadXml(item);
                    itemslist.Add(rd);


                    var dat151data = rd as Dat151RelData;
                    if (dat151data != null)
                    {
                        dat151data.NameTableOffset = ntoffset;
                    }
                    var dat4config = rd as Dat4ConfigData;
                    if (dat4config != null)
                    {
                        dat4config.NameTableOffset = ntoffset;
                    }
                    var dat4speech = rd as Dat4SpeechData;
                    if (dat4speech != null)
                    {
                        dat4speech.NameTableOffset = ntoffset;
                    }
                    var dat10item = rd as Dat10RelData;
                    if (dat10item != null)
                    {
                        dat10item.NameTableOffset = ntoffset;
                    }
                    var dat15item = rd as Dat15RelData;
                    if (dat15item != null)
                    {
                        dat15item.NameTableOffset = ntoffset;
                    }
                    var dat16item = rd as Dat16RelData;
                    if (dat16item != null)
                    {
                        dat16item.NameTableOffset = ntoffset;
                    }
                    var dat22item = rd as Dat22RelData;
                    if (dat22item != null)
                    {
                        dat22item.NameTableOffset = ntoffset;
                    }
                }

                rel.RelDatas = itemslist.ToArray();//this one will get sorted on save
                rel.RelDatasSorted = itemslist.ToArray();
            }


            return rel;
        }


        public static MetaHash GetHash(string str)
        {
            if (string.IsNullOrEmpty(str))
            {
                return 0;
            }
            if (str.StartsWith("hash_"))
            {
                return Convert.ToUInt32(str.Substring(5), 16);
            }
            else
            {
                JenkIndex.Ensure(str);
                return JenkHash.GenHash(str);
            }
        }



        public static T[] ReadItemArray<T>(XmlNode node, string name) where T : IMetaXmlItem, new()
        {
            var vnode2 = node.SelectSingleNode(name);
            if (vnode2 != null)
            {
                var inodes = vnode2.SelectNodes("Item");
                if (inodes?.Count > 0)
                {
                    var vlist = new List<T>();
                    foreach (XmlNode inode in inodes)
                    {
                        var v = new T();
                        v.ReadXml(inode);
                        vlist.Add(v);
                    }
                    return vlist.ToArray();
                }
            }
            return null;
        }
        public static MetaHash[] ReadHashItemArray(XmlNode node, string name)
        {
            var vnode = node.SelectSingleNode(name);
            if (vnode != null)
            {
                var inodes = vnode.SelectNodes("Item");
                if (inodes?.Count > 0)
                {
                    var vlist = new List<MetaHash>();
                    foreach (XmlNode inode in inodes)
                    {
                        vlist.Add(GetHash(inode.InnerText));
                    }
                    return vlist.ToArray();
                }
            }
            return null;
        }
    }



}
