//Thanks to Dimy for this method. It's nasty but it gets textures.
        //The game uses 100s of varied presets so we should try a work around for undefined presets.
        static void SetMaterialsHacky(Stream materialStream, Stream lookupStream, List <ModelChunk.MeshInfo> meshes)
        {
            List <uint[]> materialPointers = GetLookupPointers(meshes, lookupStream);

            List <uint> globalPointers = new List <uint>();

            foreach (var pointerList in materialPointers.OrderBy(x => x[0]))
            {
                for (int i = 0; i < pointerList.Length; i++)
                {
                    if (pointerList[i] != uint.MaxValue && pointerList[i] != 0)
                    {
                        globalPointers.Add(pointerList[i]);
                    }
                }
            }

            //Get lookup pointers
            using (var reader = new FileReader(materialStream, true))
            {
                for (int i = 0; i < meshes.Count; i++)
                {
                    var mat = new ModelChunk.MaterialData();
                    meshes[i].Material = mat;

                    uint[] pointers       = materialPointers[i];
                    uint   hash           = meshes[i].MeshHeader.MaterialHash;
                    string materialPreset = Hashing.CreateHashString(hash);

                    List <uint> matPointers = new List <uint>();
                    for (int j = 0; j < pointers.Length; j++)
                    {
                        if (pointers[j] != uint.MaxValue)
                        {
                            matPointers.Add(pointers[j]);
                            break;
                        }
                    }


                    var matInfo = new MaterialInfo();
                    if (!MaterialPresetInfos.ContainsKey(materialPreset))
                    {
                        MaterialPresetInfos.Add(materialPreset, matInfo);
                    }

                    var refList = pointers.ToList();
                    for (int j = 0; j < matPointers.Count; j++)
                    {
                        int pointerIndex = refList.IndexOf(matPointers[j]);

                        if (matPointers[j] % 448 == 0 || globalPointers.Contains(matPointers[j] + 448))
                        {
                            reader.SeekBegin(matPointers[j]);
                            reader.ReadBytes(12);
                            uint texhash = reader.ReadUInt32();

                            matInfo.LookupTexPointer = pointerIndex;
                            if (texhash == 0x81800000)
                            {
                                reader.Seek(-8);
                                texhash = reader.ReadUInt32();
                                if (Runtime.TextureCache.Any(x => x.Name == Hashing.CreateHashString(texhash)))
                                {
                                    matInfo.textureSlots.Add(TEXTURE_SLOT.DIFFUSE, (uint)reader.Position - matPointers[j] - 16);
                                    mat.DiffuseHash = texhash;
                                }
                                reader.ReadBytes(4);
                                uint texhash2 = reader.ReadUInt32();
                                if (Runtime.TextureCache.Any(x => x.Name == Hashing.CreateHashString(texhash2)))
                                {
                                    matInfo.textureSlots.Add(TEXTURE_SLOT.NORMAL, (uint)reader.Position - matPointers[j] - 16);
                                    mat.NormalMapHash = texhash2;
                                }
                            }
                            else
                            {
                                if (Runtime.TextureCache.Any(x => x.Name == Hashing.CreateHashString(texhash)))
                                {
                                    matInfo.textureSlots.Add(TEXTURE_SLOT.NORMAL, (uint)reader.Position - matPointers[j] - 16);
                                    mat.NormalMapHash = texhash;
                                }

                                reader.ReadBytes(8);
                                reader.ReadBytes(0xC);
                                uint texhash2 = reader.ReadUInt32();
                                if (Runtime.TextureCache.Any(x => x.Name == Hashing.CreateHashString(texhash2)))
                                {
                                    matInfo.textureSlots.Add(TEXTURE_SLOT.DIFFUSE, (uint)reader.Position - matPointers[j] - 16);
                                    mat.DiffuseHash = texhash2;
                                }
                            }
                        }
                        else if (matPointers[j] % 192 == 0 || globalPointers.Contains(matPointers[j] + 192))
                        {
                            reader.SeekBegin(matPointers[j]);
                            reader.ReadBytes(8);
                            uint texhash = reader.ReadUInt32();
                            uint a       = reader.ReadUInt32();

                            Console.WriteLine($"{materialPreset} {pointerIndex}");
                            if (texhash == 0x81800000)
                            {
                                if (Runtime.TextureCache.Any(x => x.Name == Hashing.CreateHashString(texhash)))

                                {
                                    matInfo.textureSlots.Add(TEXTURE_SLOT.NORMAL, (uint)reader.Position - matPointers[j] - 12);
                                    mat.NormalMapHash = texhash;
                                }
                                reader.ReadBytes(4);
                                reader.ReadBytes(0xC);
                                uint texhash2 = reader.ReadUInt32();
                                if (Runtime.TextureCache.Any(x => x.Name == Hashing.CreateHashString(texhash2)))
                                {
                                    Console.WriteLine($"DIFFUSE {reader.Position - matPointers[j] - 12}");
                                    mat.DiffuseHash = texhash2;
                                }
                            }
                            else
                            {
                                if (Runtime.TextureCache.Any(x => x.Name == Hashing.CreateHashString(texhash)))
                                {
                                    matInfo.textureSlots.Add(TEXTURE_SLOT.DIFFUSE, (uint)reader.Position - matPointers[j] - 12);
                                    mat.DiffuseHash = texhash;
                                }
                                reader.ReadBytes(4);
                                uint texhash2 = reader.ReadUInt32();
                                if (Runtime.TextureCache.Any(x => x.Name == Hashing.CreateHashString(texhash2)))
                                {
                                    matInfo.textureSlots.Add(TEXTURE_SLOT.NORMAL, (uint)reader.Position - matPointers[j] - 12);
                                    mat.NormalMapHash = texhash2;
                                }
                            }
                        }
                        else
                        {
                            reader.SeekBegin(matPointers[j]);
                            uint a = 0;
                            while (a != 0x81800000 && a != 0x01800000 && reader.Position < reader.BaseStream.Length - 4)
                            {
                                a = reader.ReadUInt32();
                            }
                            if (a == 0x81800000)
                            {
                                Console.WriteLine($"{materialPreset} {pointerIndex}");

                                reader.Seek(-8);
                                uint hash1 = reader.ReadUInt32();

                                if (Runtime.TextureCache.Any(x => x.Name == Hashing.CreateHashString(hash1)))
                                {
                                    matInfo.textureSlots.Add(TEXTURE_SLOT.DIFFUSE, (uint)reader.Position - matPointers[j] - 4);
                                    mat.DiffuseHash = hash1;
                                }
                                reader.ReadBytes(8);
                                uint texhash2 = reader.ReadUInt32();
                                if (Runtime.TextureCache.Any(x => x.Name == Hashing.CreateHashString(texhash2)))
                                {
                                    matInfo.textureSlots.Add(TEXTURE_SLOT.NORMAL, (uint)reader.Position - matPointers[j] - 4);
                                    mat.NormalMapHash = texhash2;
                                }
                            }
                            else if (a == 0x01800000)
                            {
                                reader.Seek(-8);
                                reader.ReadBytes(0x18);
                                uint hash1 = reader.ReadUInt32();

                                if (Runtime.TextureCache.Any(x => x.Name == Hashing.CreateHashString(hash1)))
                                {
                                    matInfo.textureSlots.Add(TEXTURE_SLOT.DIFFUSE, (uint)reader.Position - matPointers[j] - 4);
                                    mat.DiffuseHash = hash1;
                                }
                                reader.ReadBytes(8);
                                uint texhash2 = reader.ReadUInt32();
                                if (Runtime.TextureCache.Any(x => x.Name == Hashing.CreateHashString(texhash2)))
                                {
                                    matInfo.textureSlots.Add(TEXTURE_SLOT.NORMAL, (uint)reader.Position - matPointers[j] - 4);
                                    mat.NormalMapHash = texhash2;
                                }
                            }
                        }
                    }

                    if (MaterialPresetInfos[materialPreset].textureSlots.Count < matInfo.textureSlots.Count)
                    {
                        MaterialPresetInfos[materialPreset] = matInfo;
                    }
                }
            }
        }
        public static void ParseMaterials(Stream materialStream, Stream lookupStream, List <ModelChunk.MeshInfo> meshes)
        {
            SetMaterialsHacky(materialStream, lookupStream, meshes);
            foreach (var preset in MaterialPresetInfos)
            {
                Console.WriteLine($"preset {preset.Key} ptr {preset.Value.LookupTexPointer}");
                foreach (var slot in preset.Value.textureSlots)
                {
                    Console.WriteLine($"slot {slot.Key} {slot.Value}");
                }
            }

            List <uint[]> materialPointers = GetLookupPointers(meshes, lookupStream);

            //Get lookup pointers
            using (var reader = new FileReader(materialStream, true))
            {
                for (int i = 0; i < meshes.Count; i++)
                {
                    var mat = new ModelChunk.MaterialData();
                    meshes[i].Material = mat;

                    Console.WriteLine($"MESH {i}");

                    uint[] pointers       = materialPointers[i];
                    uint   hash           = meshes[i].MeshHeader.MaterialHash;
                    string materialPreset = Hashing.CreateHashString(hash);

                    List <uint> matPointers = new List <uint>();
                    for (int j = 0; j < pointers.Length; j++)
                    {
                        if (pointers[j] != uint.MaxValue && pointers[j] != 0)
                        {
                            matPointers.Add(pointers[j]);
                        }
                    }

                    var refList = pointers.ToList();
                    for (int j = 0; j < matPointers.Count; j++)
                    {
                        if (j + 1 < matPointers.Count)
                        {
                            uint size = matPointers[j + 1] - matPointers[j];
                            reader.SeekBegin(matPointers[j]);
                            while (reader.Position < matPointers[j] + size)
                            {
                                uint hashCheck = reader.ReadUInt32();
                                if (Runtime.TextureCache.Any(x => x.Name == Hashing.CreateHashString(hashCheck)))
                                {
                                    if (mat.DiffuseHash == 0)
                                    {
                                        mat.DiffuseHash = hashCheck;
                                    }

                                    Console.WriteLine($"{materialPreset} TEXTURE {hashCheck} pointer {refList.IndexOf(matPointers[j])} position {reader.Position - 4 - matPointers[j]}");
                                }
                            }
                        }
                    }

                    int textureSlotIndex = GetTextureSlotLookupIndex(materialPreset);
                    Console.WriteLine($"textureSlotIndex");
                    if (textureSlotIndex != -1)
                    {
                        var textureSlots = GetTextureSlotsOffset(materialPreset);
                        if (textureSlots.ContainsKey(TEXTURE_SLOT.DIFFUSE))
                        {
                            reader.SeekBegin(pointers[textureSlotIndex] + textureSlots[TEXTURE_SLOT.DIFFUSE]);
                            mat.DiffuseHash = reader.ReadUInt32();
                        }
                        if (textureSlots.ContainsKey(TEXTURE_SLOT.NORMAL))
                        {
                            reader.SeekBegin(pointers[textureSlotIndex] + textureSlots[TEXTURE_SLOT.NORMAL]);
                            mat.NormalMapHash = reader.ReadUInt32();
                        }
                    }
                }
            }
        }