public override AquaObject Clone()
        {
            NGSAquaObject aqp = new NGSAquaObject();

            aqp.afp      = afp;
            aqp.objc     = objc;
            aqp.vsetList = new List <VSET>(vsetList);
            aqp.vtxeList = vtxeList.ConvertAll(vtxe => vtxe.Clone()).ToList();
            aqp.vtxlList = vtxlList.ConvertAll(vtxl => vtxl.Clone()).ToList();
            aqp.psetList = new List <PSET>(psetList);
            aqp.meshList = new List <MESH>(meshList);
            aqp.mateList = new List <MATE>(mateList);
            aqp.rendList = new List <REND>(rendList);
            aqp.shadList = shadList.ConvertAll(shad => shad.Clone()).ToList();
            aqp.tstaList = new List <TSTA>(tstaList);
            aqp.tsetList = tsetList.ConvertAll(tset => tset.Clone()).ToList();
            aqp.texfList = new List <TEXF>(texfList);
            if (aqp.unrms != null)
            {
                aqp.unrms = unrms.Clone();
            }
            aqp.strips = strips.ConvertAll(stp => stp.Clone()).ToList();

            //*** 0xC33 only
            aqp.bonePalette = new List <uint>(bonePalette);

            //Unclear the purpose of these, but when present they have a smaller count than initial mesh and psets.
            aqp.unkStruct1List = new List <unkStruct1>(unkStruct1List);
            aqp.mesh2List      = new List <MESH>(mesh2List);
            aqp.pset2List      = new List <PSET>(pset2List);
            aqp.strips2        = strips2.ConvertAll(stp => stp.Clone()).ToList();

            aqp.strips3Lengths = new List <int>(strips3Lengths);
            aqp.strips3        = strips3.ConvertAll(stp => stp.Clone()).ToList();
            aqp.unkPointArray1 = new List <Vector3>(unkPointArray1); //Noooooooo idea what these are. Count matches the strips3Lengths count
            aqp.unkPointArray2 = new List <Vector3>(unkPointArray2);
            //***

            aqp.applyNormalAveraging = applyNormalAveraging;

            //Custom model related data
            aqp.tempTris = tempTris.ConvertAll(tri => tri.Clone()).ToList();
            aqp.tempMats = tempMats.ConvertAll(mat => mat.Clone()).ToList();

            return(aqp);
        }
        //Takes in an Assimp model and generates a full PSO2 model and skeleton from it.
        public static AquaObject AssimpAquaConvertFull(string initialFilePath, float scaleFactor, bool preAssignNodeIds, bool isNGS)
        {
            AquaUtil aquaUtil  = new AquaUtil();
            float    baseScale = 1f / 100f * scaleFactor; //We assume that this will be 100x the true scale because 1 unit to 1 meter isn't the norm

            Assimp.AssimpContext context = new Assimp.AssimpContext();
            context.SetConfig(new Assimp.Configs.FBXPreservePivotsConfig(false));
            Assimp.Scene aiScene = context.ImportFile(initialFilePath, Assimp.PostProcessSteps.Triangulate | Assimp.PostProcessSteps.JoinIdenticalVertices | Assimp.PostProcessSteps.FlipUVs);

            AquaObject aqp;
            AquaNode   aqn = new AquaNode();

            if (isNGS)
            {
                aqp = new NGSAquaObject();
            }
            else
            {
                aqp = new ClassicAquaObject();
            }

            //Construct Materials
            Dictionary <string, int> matNameTracker = new Dictionary <string, int>();

            foreach (var aiMat in aiScene.Materials)
            {
                string name;
                if (matNameTracker.ContainsKey(aiMat.Name))
                {
                    name = $"{aiMat.Name} ({matNameTracker[aiMat.Name]})";
                    matNameTracker[aiMat.Name] += 1;
                }
                else
                {
                    name = aiMat.Name;
                    matNameTracker.Add(aiMat.Name, 1);
                }

                AquaObject.GenericMaterial genMat = new AquaObject.GenericMaterial();
                List <string> shaderList          = new List <string>();
                AquaObjectMethods.GetMaterialNameData(ref name, shaderList, out string alphaType, out string playerFlag);
                genMat.matName     = name;
                genMat.shaderNames = shaderList;
                genMat.blendType   = alphaType;
                genMat.specialType = playerFlag;
                genMat.texNames    = new List <string>();
                genMat.texUVSets   = new List <int>();

                //Texture assignments. Since we can't rely on these to export properly, we dummy them or just put diffuse if a playerFlag isn't defined.
                //We'll have the user set these later if needed.
                if (genMat.specialType != null)
                {
                    AquaObjectMethods.GenerateSpecialMaterialParameters(genMat);
                }
                else if (aiMat.TextureDiffuse.FilePath != null)
                {
                    genMat.texNames.Add(Path.GetFileName(aiMat.TextureDiffuse.FilePath));
                }
                else
                {
                    genMat.texNames.Add("tex0_d.dds");
                }
                genMat.texUVSets.Add(0);

                AquaObjectMethods.GenerateMaterial(aqp, genMat, true);
            }

            //Default to this so ids can be assigned by order if needed
            Dictionary <string, int> boneDict = new Dictionary <string, int>();

            if (aiScene.RootNode.Name == null || !aiScene.RootNode.Name.Contains("(") || preAssignNodeIds == true)
            {
                int nodeCounter = 0;
                BuildAiNodeDictionary(aiScene.RootNode, ref nodeCounter, boneDict);
            }

            IterateAiNodesAQP(aqp, aqn, aiScene, aiScene.RootNode, Matrix4x4.Transpose(GetMat4FromAssimpMat4(aiScene.RootNode.Transform)), baseScale);

            //Assimp data is gathered, proceed to processing model data for PSO2
            AquaUtil.ModelSet set = new AquaUtil.ModelSet();
            set.models.Add(aqp);
            aquaUtil.aquaModels.Add(set);
            aquaUtil.ConvertToNGSPSO2Mesh(false, false, false, true, false, false, true);

            //AQPs created this way will require more processing to finish.
            //-Texture lists in particular, MUST be generated as what exists is not valid without serious errors
            return(aqp);
        }